Merge origin/main 5ca8324b into issue-3; reconcile validator gates (governor 10637 / owner guidance 2026-08-29)
Magic/Alchemy PR #10 landed on main; this integrates it into the woodcutting branch and resolves the predicted tools/validate.py conflict: - union of all validator gates: magic/alchemy (recipe/rate/tier/loadout, supply_limit_conflicts, document_error + _end_to_end_bad_mapping), mining (pickaxe suite), GE-flip lifecycle (floor-tax + scheduler + conservation + slot-phase + buy-capacity + slot-reuse), and the woodcutting gates (canonical axe table, per-mode ladders, per-selected- row 27/28 dynamic rates, drop-GP-zero, prepare/failed/drop-gate wiring). - governor 10637: removed the run_flip_selftest alias duplication — the combined GE/Woodcutting suite no longer runs twice. Each suite now runs exactly once per invocation: run_selftest (cross-field/alchemy), run_flip_selftest (GE lifecycle), run_mining_selftest, and the new run_woodcutting_selftest. Truthful unique selftest count: 144 PASS. - tree scan: 6 entries, 0 errors, 0 warnings; git diff --check clean.
This commit is contained in:
commit
0c2e38c998
@ -3,83 +3,189 @@ title: Low-Level Alchemy (F2P)
|
||||
domain: economy
|
||||
tags: [alching, magic-training, f2p, loss-training]
|
||||
status: verified
|
||||
version: 1
|
||||
updated: "2026-08-27" # ISO dates must stay quoted — YAML 1.1 parses bare dates to datetime.date
|
||||
version: 4 # 4: bounce-fix 6 2026-08-28 (governor comment 10394, PR #10) — real build-loadout action a8 (verified collected staff/candidate/natures, overflow deposit, bank-stock-shortfall-only withdrawal, carried counts PROVEN before the first cast a9; action ids renumbered a9-a13), capital-loss stop sign corrected (initial capital - total assets > 684,400), Magic target pinned at 55 (the LA -> HLA handoff; 54 is a continue), GP bounds tied to the two declared fill scenarios (max-fill net -126.6 -> low -123,700; live-low net -112 -> high -65,600). 3: bounce-fix 4 2026-08-28 (owner guidance 10331, PR #10) — explicit rate_model (session-realized rates incl. startup over a 2h horizon: xp 23,000, gp -109,500..-65,600), complete GE acquisition path (open -> fill -> collect) for the initial buy AND every restock (bank-stock fast path), fail-closed staff equip, monotonic break example (550/1,100/1,650 independent of 901-cast restocks), assets-based capital stops
|
||||
updated: "2026-08-28" # ISO dates must stay quoted — YAML 1.1 parses bare dates to datetime.date
|
||||
|
||||
summary: >
|
||||
Magic training from level 21 by low-alching F2P items with the highest
|
||||
lowalch-value among affordable, high-limit items. At current prices it is
|
||||
a LOSS activity (money in exchange for Magic XP); run it only for XP.
|
||||
Model pins (owner guidance 2026-08-28): one iteration = one cast; breaks
|
||||
every 400-700 COMPLETED CASTS (cast-count based, independent of bank
|
||||
visits — midpoint example 550, 1,100, 1,650, ...); restock when candidate
|
||||
or nature drops below the numeric restock_threshold (100) against a
|
||||
carried_batch of 1,000/1,000 (restock cadence 901 casts, monotonic and
|
||||
independent of breaks). EVERY purchase follows the complete GE path open
|
||||
-> place -> fill/wait -> collect, for the initial acquisition and for
|
||||
every restock (a bank-stock fast path applies only when the bank actually
|
||||
holds enough stock). Staff-of-fire equip failure is FAIL-CLOSED (bounded
|
||||
retries, then log ERROR + alert + stop — no fire-rune fallback is
|
||||
modeled). Session horizon 2 h; all rates are SESSION-REALIZED under the
|
||||
declared rate_model (startup + restock + breaks included; see economy).
|
||||
|
||||
accounts:
|
||||
membership: f2p
|
||||
min_level: 21 # Magic 21 to cast Low Level Alchemy (wiki-verified)
|
||||
requires_quest: []
|
||||
requires_other:
|
||||
- "Staff of Fire equipped (removes 3 fire runes from the cost)"
|
||||
- "A bank with GE access within reach"
|
||||
- "Staff of Fire equipped (removes 3 fire runes from the cost; NO level requirement documented on the OSRS wiki — verified 2026-08-28, see sources). Equip failure is FAIL-CLOSED: bounded retries (3), then log ERROR + alert + stop — there is no fire-rune fallback in this model"
|
||||
- "A bank with GE access within reach (alch spot = the bank booth; restock trip [60, 120] s)"
|
||||
- "Starting capital >= ~1.30M gp CASH (staff hard cap 5,000 + first batch 1,000/1,000 at MAX allowed fill 306,600 + session loss reserve 684,400 = 6 worst-case 901-cast batches at live-low+5% fills (covers Magic 21 -> 55) + resting-offer float 306,600). The capital stop checks TOTAL ASSETS (cash + supplies at current buy cost), never raw cash — cash legitimately converts into supplies mid-run"
|
||||
|
||||
best_practice:
|
||||
equipment:
|
||||
- item: staff of fire
|
||||
why: "unlimited fire runes — LA rune cost drops from 3 fire + 1 nature to 1 nature per cast (~15gp/cycle saved)"
|
||||
source: "OSRS wiki — Staff of Fire; Low Level Alchemy (Cost)"
|
||||
why: "unlimited fire runes — LA rune cost drops from 3 fire + 1 nature to 1 nature per cast (~15gp/cycle saved); equip requirement: none documented on the OSRS wiki (verified 2026-08-28); if it cannot be equipped after bounded retries the run FAILS CLOSED (no fallback modeled)"
|
||||
source: "OSRS wiki — Staff of fire (id 1387: no requirements row in the infobox, none in the prose — contrast Battlestaff 'requires 30 Attack and 30 Magic'); Low Level Alchemy (Cost)"
|
||||
techniques:
|
||||
- name: cast on noted (stacked) items
|
||||
why: "one inventory slot, minimal mouse travel between spell icon and item"
|
||||
why: "one inventory slot, minimal mouse travel between spell icon and item; means an inventory does NOT define a batch size — batch sizes are the explicit numeric carried_batch below"
|
||||
source: "OSRS wiki — Low Level Alchemy (Usage: casting alchemy spells on noted items)"
|
||||
- name: bank at a GE-adjacent bank
|
||||
why: "supply restock without a second travel leg"
|
||||
source: "researched 2026-08-27 (standard operator practice; wiki LA Cost section corroborates rune economy)"
|
||||
why: "supply restock without a second travel leg — runes and alch items both come from the GE; restock trip 60-120s"
|
||||
source: "OSRS wiki — Money making guide/High alching profitable free-to-play items (bulk alching via noted items; West Varrock Bank is the common F2P alch/trade hub); OSRS wiki — High Level Alchemy (buying GE items below alch value for break-even/profit; noted-item casting saves bank withdrawals)"
|
||||
|
||||
economy:
|
||||
# Verified 2026-08-27 against prices.runescape.wiki (live 'latest')
|
||||
# + OSRS wiki Low_Level_Alchemy infobox.
|
||||
# Bounce-fix 6 (2026-08-28, governor comment 10394): the GP bounds are tied
|
||||
# to the DECLARED actual-fill scenarios with the SAME costs as the capital
|
||||
# model — live-low fills (net -112/cast: 148 + 144) and MAX allowed fills
|
||||
# (live low + 5 %: 155.4 + 151.2 = 306.6 -> net -126.6/cast), because the
|
||||
# executable purchase accepts live low + 5 % (a4/a10 max_price).
|
||||
item: Gold necklace # example anchor; rank by cheapest candidate live
|
||||
item_id: 1654
|
||||
cost_per_cycle: 292 # necklace buy 148 + nature rune 144 (staff of fire)
|
||||
cost_per_cycle: 292 # necklace buy 148 + nature rune 144 (staff of fire, live low)
|
||||
cost_per_cycle_max_fill: 306.6 # live low + 5 %: 155.4 + 151.2 (same costs as the capital model)
|
||||
income_per_cycle: 180 # lowalch of gold necklace (40% of value 450)
|
||||
net_per_cycle: -112
|
||||
gp_per_hour_low: -250000 # negative: this burns GP
|
||||
gp_per_hour_high: -200000
|
||||
xp_per_hour: 55800 # 31 xp/cast (wiki) @ ~1800 casts/hr (3-tick, wiki)
|
||||
net_per_cycle: -112 # at live-low fills
|
||||
net_per_cycle_max_fill: -126.6 # at MAX allowed fills (worst declared scenario)
|
||||
gp_per_hour_low: -123700 # session-realized WORST declared scenario: 977.1 casts/hr x -126.6 (max-fill) = -123,700 (fast 3.4s cycle, 300s startup, 2h horizon)
|
||||
gp_per_hour_high: -65600 # session-realized BEST declared scenario: 585.9 casts/hr x -112 (live-low) = -65,621 (slow 5.2s cycle, 600s startup, 2h horizon)
|
||||
xp_per_hour: 23000 # session-realized midpoint: 741.8 casts/hr x 31 = 22,995 (pin 23,000)
|
||||
# ---- rate model (derived; enforced by tools/validate.py rate_model_errors) ----
|
||||
# Cast: 1.8s (3 ticks x 0.6s, rate_model.cast_ticks) + anti_ban.delay
|
||||
# [1.6, 3.4]s ADDITIVE (action-grammar.md:135) = 3.4-5.2s, midpoint 4.3s.
|
||||
# BATCH model: carried_batch 1,000 candidate + 1,000 natures; restock_threshold
|
||||
# 100 -> 901-cast restock cadence. Overhead per 901-cast batch: restock trip
|
||||
# [60, 120]s (mid 90) + breaks (every [400, 700] casts, mid 550, for
|
||||
# [45, 120]s, mid 82.5s -> 82.5 x 901/550 = 135.2s).
|
||||
# STEADY-STATE casts/hr = 901 x 3600 / (901 x cycle + trip + break_share x 901):
|
||||
# fast 3.4s -> 1,019.7; midpoint 4.3s -> 791.3; slow 5.2s -> 639.2.
|
||||
# SESSION-REALIZED (2 h horizon = 7,200 s; startup 300-600 s, mid 450 s ->
|
||||
# 450/7200 = 6.25 % amortised): 977.1 / 741.8 / 585.9 casts/hr.
|
||||
# xp_per_hour = 741.8 x 31 = 22,995 (pin 23,000);
|
||||
# gp_per_hour = casts/hr x net-per-cast over the TWO declared fill
|
||||
# scenarios (same costs as the capital model):
|
||||
# worst = fast casts/hr x max-fill net: 977.1 x -126.6 = -123,700 (low)
|
||||
# best = slow casts/hr x live-low net: 585.9 x -112 = -65,621 (high)
|
||||
# (mid x mid-fill -119.3 = -88,497 is inside the band)
|
||||
# BATCH ECONOMICS (901 casts; deposits 901 x 180 = 162,180 gp per batch):
|
||||
# input cost at live low: 901 x 292 = 263,092 -> net -100,912/batch.
|
||||
# input cost at MAX fill (live low + 5 %: 1,000 x 155.4 + 1,000 x 151.2 =
|
||||
# 306,600 per batch): 901 x 306.6 = 276,247 -> net -114,067/batch (worst
|
||||
# case). Reserve = 6 worst-case batches (Magic 21 -> 55) = 684,400 gp;
|
||||
# the capital stops check TOTAL ASSETS, not raw cash (accounts + stop_conditions).
|
||||
# Superseded figures (all fail the derived gate on purpose): loop-only 837
|
||||
# casts/hr (25,953 xp/hr); the 8-14-cast-break regime (~305 casts/hr); the
|
||||
# 1,800-cast regime; the pre-startup realized 24,500 (791.3 x 31) — startup
|
||||
# amortisation is part of the model.
|
||||
supplies:
|
||||
- item: gold necklace
|
||||
qty_per_cycle: 1
|
||||
source: ge
|
||||
ge_limit: 18000 # mapping 'limit', wiki-verified
|
||||
ge_limit: 18000 # mapping 'limit', wiki-verified; one carried_batch of 1,000 fits the 4h window
|
||||
- item: nature rune
|
||||
qty_per_cycle: 1
|
||||
source: ge
|
||||
ge_limit: 12500
|
||||
ge_limit: 18000 # mapping 'limit' + Module:Exchange/Nature_rune agree;
|
||||
# matches magic-alch-handoff (consistency check enforces)
|
||||
profit_drivers:
|
||||
- "NONE at current prices — XP is the product, not GP"
|
||||
- "Pick the candidate with the least-negative net each run (live rank)"
|
||||
- "Batch-scale economics (worst case 1 nature/cast): carried_batch 1,000/1,000, restock every 901 casts — one batch = 901 x -112 = -100,912 gp at live-low fills (-114,067 at MAX allowed fills), +27,931 xp, deposits 162,180 gp"
|
||||
|
||||
# Explicit activity/rate discriminator (owner guidance 2026-08-28, bounce 4):
|
||||
# this entry OPTS IN to the derived-rate gate; every rate derives from the
|
||||
# entry's own declared lifecycle and the validator re-derives it.
|
||||
rate_model:
|
||||
anchor_tier: la # xp_per_hour pins the LA tier's realized rate
|
||||
cast_ticks: 3 # LA is a 3-tick cast -> 1.8 s (0.6 s/tick)
|
||||
restock_trip_s: [60, 120] # GE-adjacent booth trip per restock
|
||||
session_horizon_s: 7200 # 2 h session; startup is amortised over it
|
||||
startup_s: [300, 600] # one-time GE acquisition + loadout
|
||||
alch_carry_batch: 1000 # stacked candidates + natures
|
||||
alch_restock_threshold: 100 # -> 901-cast LA restock cadence
|
||||
|
||||
state_machine:
|
||||
initial: idle
|
||||
terminal: [complete, failed]
|
||||
states:
|
||||
idle:
|
||||
goal: reach the bank + have supplies in inventory
|
||||
next: [casting, bank_supplies]
|
||||
goal: "session start at the GE bank booth. Open GE (a2), then place the initial offers: staff of fire (a3), candidate 1,000 (a4), nature runes 1,000 (a5) at live low + 5% (staff: +25% up to the 5,000 cap). Record initial capital in the cash ledger (total assets = cash + supplies at current buy cost). Nothing is bought or collected without an open GE interface"
|
||||
next: [wait_offers, complete, failed]
|
||||
wait_offers:
|
||||
goal: "wait for the pending offers (ge_offers_done); when filled, collect every purchase + refund from the collection box (a6 — never leave purchases in the box). PARTIAL FILLS: collect the filled portion, re-place the remainder at the current edge (a4/a5); 3 consecutive no-fill rounds -> failed. An offer still unfilled at session end is left resting by design — its coins are tied up (float reserve) and return when it fills or the operator aborts it (the single operator-touch point)"
|
||||
next: [ready, wait_offers, failed]
|
||||
ready:
|
||||
goal: "equip the staff of fire (a7 — bounded retries, then FAIL CLOSED) and build the VERIFIED loadout (a8 build-loadout): verify the collected staff + candidate + natures (from a6), deposit overflow, withdraw only the real bank-stock shortfall, and PROVE the carried counts equal carried_batch 1,000/1,000 BEFORE the first cast (a9)"
|
||||
next: [casting, bank_supplies, failed]
|
||||
casting:
|
||||
goal: cast Low Level Alchemy on the current candidate item
|
||||
next: [bank_supplies, idle, complete, failed]
|
||||
goal: "cast Low Level Alchemy on the current candidate item (a9) — each cast consumes 1 candidate + 1 nature and pays 180 gp (lowalch), +31 xp, net -112 gp at live-low fills; take a break when the completed-cast counter hits run_control.break.every ([400, 700] casts, via a13); the counter is NEVER reset by restocking"
|
||||
next: [bank_supplies, complete, failed]
|
||||
bank_supplies:
|
||||
goal: bank the produced coins, withdraw fresh candidate + runes
|
||||
next: [casting, idle]
|
||||
goal: "restock to carried_batch: deposit coins + products and withdraw ALL candidate/natures the bank holds (a10 — bank-stock fast path when the bank already holds enough); for the remaining deficit, open GE (a2), buy the deficit (a11, live low + 5%), collect it (a12) — never withdraw a batch that was never bought. Restocking never resets the cast counter or the break counter; the break cadence (550/1,100/1,650, ...) is independent of the restock cadence (901/1,802, ...)"
|
||||
next: [casting, bank_supplies, failed]
|
||||
complete:
|
||||
goal: reached the run's XP/level target
|
||||
goal: "reached the run's XP/level target (default 55 — the LA -> HLA handoff) or the 2 h session horizon"
|
||||
failed:
|
||||
goal: hard failure — stop, log ERROR sentinel, alert
|
||||
goal: "hard failure — stop, log ERROR sentinel, alert"
|
||||
transitions:
|
||||
- from: casting
|
||||
when: "candidate item count < buffer OR nature rune count < buffer"
|
||||
to: bank_supplies
|
||||
- from: idle
|
||||
when: "magic level >= target (default 54, hand off to HLA at 55)"
|
||||
when: "staff + candidate + nature offers all placed (a3/a4/a5)"
|
||||
to: wait_offers
|
||||
- from: idle
|
||||
when: "magic level >= target (55 — the LA -> HLA handoff) at session start"
|
||||
to: complete
|
||||
- from: idle
|
||||
when: "3 consecutive offer-place failures at session start (no fallback candidate)"
|
||||
to: failed
|
||||
- from: wait_offers
|
||||
when: "ge_offers_done AND all purchases collected (a6)"
|
||||
to: ready
|
||||
- from: wait_offers
|
||||
when: "partial fill: filled portion collected (a6), remainder re-placed at the current edge (a4/a5) — still waiting"
|
||||
to: wait_offers
|
||||
- from: wait_offers
|
||||
when: "3 consecutive no-fill rounds (offer cannot fill at the accepted edge)"
|
||||
to: failed
|
||||
- from: ready
|
||||
when: "staff equipped (a7) AND build-loadout verified the carried counts at carried_batch 1,000/1,000 (a8 — collected staff/candidate/natures present, overflow deposited, only a real bank-stock shortfall withdrawn)"
|
||||
to: casting
|
||||
- from: ready
|
||||
when: "staff equip failed after bounded retries — FAIL CLOSED"
|
||||
to: failed
|
||||
- from: ready
|
||||
when: "build-loadout verification shows a carried shortfall (candidate or nature < carried_batch) that the bank does not hold — restock first"
|
||||
to: bank_supplies
|
||||
- from: casting
|
||||
when: "candidate count < restock_threshold (100) OR nature count < restock_threshold (100) — deterministic restock trigger, pinned numbers"
|
||||
to: bank_supplies
|
||||
- from: casting
|
||||
when: "magic level >= target (55 — the LA -> HLA handoff; level 54 is a CONTINUE: LA keeps casting until the handoff boundary)"
|
||||
to: complete
|
||||
- from: casting
|
||||
when: "3 consecutive failed casts (client issue — do not loop)"
|
||||
to: failed
|
||||
- from: bank_supplies
|
||||
when: "restocked to carried_batch (1,000 candidate + 1,000 nature) — bank fast path or re-bought deficit collected"
|
||||
to: casting
|
||||
- from: bank_supplies
|
||||
when: "restock partial: deficit re-bought but offers still filling (ge_offers_done false) — loop the restock phase"
|
||||
to: bank_supplies
|
||||
- from: bank_supplies
|
||||
when: "3 consecutive no-fill restock rounds OR a capital stop fires (assets / loss-reserve checks in stop_conditions)"
|
||||
to: failed
|
||||
|
||||
actions:
|
||||
- id: a1
|
||||
@ -87,25 +193,95 @@ actions:
|
||||
verb: move_to
|
||||
target: bank
|
||||
params:
|
||||
location: "nearest bank with GE"
|
||||
location: "GE-adjacent bank (alch spot = the bank booth, so restock is a single short leg)"
|
||||
method: [teleport, walk]
|
||||
on_fail: retry
|
||||
anti_ban:
|
||||
delay: [400, 1600]
|
||||
|
||||
- id: a2
|
||||
step: buy-supplies
|
||||
step: open-ge
|
||||
verb: ge_open
|
||||
target: grand-exchange
|
||||
params:
|
||||
note: "open the GE interface at the booth. The entry NEVER buys (a3/a4/a5/a10) or collects (a6/a11) without an open GE interface — the action grammar defines ge_open, ge_buy, ge_collect as separate verbs, so the open step is explicit"
|
||||
on_fail: retry
|
||||
anti_ban:
|
||||
delay: [600, 1400]
|
||||
|
||||
- id: a3
|
||||
step: buy-staff
|
||||
verb: ge_buy
|
||||
target: grand-exchange
|
||||
params:
|
||||
item: "current candidate item"
|
||||
qty: "fill to buffer"
|
||||
max_price: "live low + 5%"
|
||||
item: "staff of fire"
|
||||
qty: 1
|
||||
max_price: "live low + 25 % (wiki value 1,500; hard cap 5,000)"
|
||||
note: "offer rests until filled or the run ends; on a partial/no fill, collect what filled (a6) and re-place the remainder at the current edge — bounded retries, then the run fails closed (no fire-rune fallback exists)"
|
||||
on_fail: retry
|
||||
anti_ban:
|
||||
delay: [1200, 3000]
|
||||
|
||||
- id: a3
|
||||
- id: a4
|
||||
step: buy-supplies
|
||||
verb: ge_buy
|
||||
target: grand-exchange
|
||||
params:
|
||||
item: "current least-loss live candidate (default: gold necklace)"
|
||||
qty: "carried_batch = 1,000 (fits the 4h GE limit window of 18,000)"
|
||||
max_price: "live low + 5 %"
|
||||
note: "offer rests until filled or the run ends; on a partial fill, collect the filled portion (a6) and re-place the remainder at the current edge"
|
||||
on_fail: retry
|
||||
anti_ban:
|
||||
delay: [1200, 3000]
|
||||
|
||||
- id: a5
|
||||
step: buy-natures
|
||||
verb: ge_buy
|
||||
target: grand-exchange
|
||||
params:
|
||||
item: "nature rune"
|
||||
qty: "carried_batch = 1,000 (4h GE limit 18,000)"
|
||||
max_price: "live low + 5 %"
|
||||
note: "offer rests until filled or the run ends; partial fills handled like a4"
|
||||
on_fail: retry
|
||||
anti_ban:
|
||||
delay: [1200, 3000]
|
||||
|
||||
- id: a6
|
||||
step: collect-purchases
|
||||
verb: ge_collect
|
||||
target: grand-exchange
|
||||
params:
|
||||
note: "collect every filled purchase and refund from the GE collection box into the inventory — staff, candidate, natures (and the equivalent on every restock). Partial offers: the collected portion is added to the ledger; nothing is left in the box at session start"
|
||||
on_fail: retry
|
||||
anti_ban:
|
||||
delay: [600, 1400]
|
||||
|
||||
- id: a7
|
||||
step: equip-staff
|
||||
verb: menu_option
|
||||
target: "staff of fire in inventory"
|
||||
params:
|
||||
option: "Wield"
|
||||
note: "Equip requirement is NONE documented on the OSRS wiki Staff of fire page (no requirements row in the infobox, none in the prose; compare Battlestaff 'requires 30 Attack and 30 Magic'; verified 2026-08-28). FAIL-CLOSED path: bounded retries (3), then log ERROR + alert + stop — no fire-rune fallback is modeled (never loop on equip attempts)"
|
||||
on_fail: retry
|
||||
anti_ban:
|
||||
delay: [600, 1800]
|
||||
|
||||
- id: a8
|
||||
step: build-loadout
|
||||
verb: bank_inventory
|
||||
target: bank
|
||||
params:
|
||||
deposit: [overflow products]
|
||||
withdraw: "only the real bank-stock shortfall up to carried_batch (1,000 candidate + 1,000 nature) — the purchases collected by a6 are already in the inventory; a deficit the bank does not actually hold is NEVER withdrawn (it is bought at the GE via the bank_supplies phase, a11)"
|
||||
verify: "staff of fire collected and present (a6), candidate count == carried_batch 1,000, nature count == carried_batch 1,000 — the carried counts are PROVEN before the first cast (a9); a verified shortfall sends the slot to bank_supplies instead of casting"
|
||||
on_fail: retry
|
||||
anti_ban:
|
||||
delay: [500, 1100]
|
||||
|
||||
- id: a9
|
||||
step: cast-alch
|
||||
verb: use_item_on
|
||||
target: "candidate item in inventory"
|
||||
@ -113,43 +289,153 @@ actions:
|
||||
spell: "Low Level Alchemy"
|
||||
item: "cheapest live candidate in inventory"
|
||||
on: "itself"
|
||||
consumption: "1 candidate + 1 nature per cast (staff of fire default); pays 180 gp (lowalch) + 31 xp, net -112 gp at live-low fills"
|
||||
on_fail: retry
|
||||
anti_ban:
|
||||
delay: [1600, 3400] # 3-tick cast = ~5.4s game; stay under it, humanised
|
||||
delay: [1600, 3400] # MANDATORY post-action sleep, ADDITIVE to the 1.8s cast (3 ticks x 0.6s; action-grammar.md:135): cycle = 1.8s + 1.6-3.4s = 3.4-5.2s, midpoint 4.3s -> session-realized ~742 casts/hr incl. startup + restock + breaks (rate_model)
|
||||
|
||||
- id: a4
|
||||
step: bank-loop
|
||||
- id: a10
|
||||
step: restock-deposit
|
||||
verb: bank_inventory
|
||||
target: bank
|
||||
params:
|
||||
deposit: [all coins, all products]
|
||||
withdraw: "candidate item + nature runes up to buffer"
|
||||
withdraw: "ALL candidate + nature runes currently in the bank, up to carried_batch (1,000/1,000) — the bank-stock FAST PATH applies only when the bank actually holds enough stock; the remaining deficit is bought at the GE (a11) and collected (a12)"
|
||||
on_fail: alert
|
||||
anti_ban:
|
||||
delay: [500, 1100]
|
||||
|
||||
- id: a11
|
||||
step: restock-buy
|
||||
verb: ge_buy
|
||||
target: grand-exchange
|
||||
params:
|
||||
item: "current least-loss live candidate + nature runes"
|
||||
qty: "deficit to carried_batch = carried_batch - inventory count after the a10 fast path (e.g. 901 candidate + 901 nature after a 901-cast batch with an empty bank)"
|
||||
max_price: "live low + 5 %"
|
||||
note: "the deficit is RE-BOUGHT at the GE on every restock — the entry never withdraws a batch that was never purchased; partial/failed fills use the same collect + re-place recovery as the initial acquisition"
|
||||
on_fail: retry
|
||||
anti_ban:
|
||||
delay: [1200, 3000]
|
||||
|
||||
- id: a12
|
||||
step: restock-collect
|
||||
verb: ge_collect
|
||||
target: grand-exchange
|
||||
params:
|
||||
note: "collect the re-bought deficit into the inventory — inventory returns to carried_batch 1,000/1,000 before casting resumes"
|
||||
on_fail: retry
|
||||
anti_ban:
|
||||
delay: [600, 1400]
|
||||
|
||||
- id: a13
|
||||
step: take-break
|
||||
verb: take_break
|
||||
target: "current location"
|
||||
params:
|
||||
duration: "[45, 120] seconds of idle AFK per break (matches run_control.break.for)"
|
||||
note: "executed by the translator when the completed-cast counter reaches run_control.break.every — this IS run_control.break's executor, fired on CAST COUNTS, not on bank visits; the cast counter is NOT reset by restocking (breaks land at 550/1,100/1,650 in the midpoint example, independent of the 901-cast restock cadence)"
|
||||
on_fail: skip
|
||||
|
||||
run_control:
|
||||
iteration: "one cast"
|
||||
max_iterations: null
|
||||
iteration: "one cast" # = one Low Level Alchemy cast (+31 xp, -112 gp at the anchor). Per docs/schema.md run_control, break.every counts ITERATIONS — so it counts CASTS here, NOT bank trips (owner decision 2026-08-28)
|
||||
max_iterations: null # null = until complete condition
|
||||
break:
|
||||
every: [8, 14] # bank cycles (breaks land on bank visits)
|
||||
for: [45, 120] # seconds of idle AFK
|
||||
every: [400, 700] # COMPLETED CASTS between AFK breaks (midpoint 550 = ~39 min at the 4.3s midpoint cycle). Cast-count-based and independent of bank visits; a restock trip NEVER counts as a break and does not reset this counter
|
||||
for: [45, 120] # seconds of idle AFK per break
|
||||
stop_conditions:
|
||||
- "magic level >= target"
|
||||
- "gp under floor"
|
||||
- "magic level >= target (55 — the LA -> HLA handoff)"
|
||||
- "session elapsed >= 2 h (session horizon — startup is amortised over this window in the rate model)"
|
||||
- "total assets (cash + supplies at current buy cost) < 311,600 — cannot fund the next batch at max fill (306,600) plus staff replacement (5,000); assets, NOT raw cash: cash that became supplies is not a loss"
|
||||
- "session net loss = initial capital - total assets > 684,400 — the 6-batch worst-case loss reserve is exhausted (a loss is WHEN ASSETS FALL; total assets - initial capital goes NEGATIVE on losses and can never exceed the reserve — the reversed sign never fires)"
|
||||
- "3 consecutive failed casts (client issue — do not loop)"
|
||||
- "3 consecutive no-fill GE rounds (initial acquisition or restock) with no fallback candidate available"
|
||||
- "staff of fire equip failed after bounded retries — FAIL CLOSED (log ERROR, alert, stop)"
|
||||
|
||||
# ================= WORKED EXAMPLE (pinned, deterministic — owner guidance 2026-08-28) =================
|
||||
# Constants: carried_batch = 1,000 candidate + 1,000 nature; restock_threshold = 100;
|
||||
# break.every = [400, 700] casts — the example pins the MIDPOINT 550;
|
||||
# break.for = [45, 120] s; restock cadence = 901 casts (1,000 - 99); the
|
||||
# staff-of-fire path consumes 1 candidate + 1 nature per cast (worst case 1:1).
|
||||
# The two counters are MONOTONIC and INDEPENDENT: breaks at 550, 1,100, 1,650,
|
||||
# 2,200... (multiples of 550) and restocks at 901, 1,802, 2,703... (multiples
|
||||
# of 901) — gcd(550, 901) = 1, so they interleave forever and restocking NEVER
|
||||
# resets or shifts the break counter.
|
||||
#
|
||||
# Step 0 — preparation (one-time startup, ~300-600 s): account holds >= ~1.30M
|
||||
# gp cash (staff cap 5,000 + first batch max 306,600 + reserve 684,400 +
|
||||
# float 306,600). At the GE bank: open GE (a2); place offers — staff (a3),
|
||||
# 1,000 gold necklaces (a4), 1,000 nature runes (a5); wait for fills
|
||||
# (ge_offers_done) and collect everything (a6); equip the staff (a7); loadout
|
||||
# = carried_batch 1,000/1,000 (a8). Cast counter := 0; cash ledger opened.
|
||||
# Step 1 — casts #1..#550: each cast consumes 1 candidate + 1 nature (-292 gp)
|
||||
# and pays 180 gp (lowalch) + 31 xp -> net -112 gp. Cast counter 0 -> 550
|
||||
# (~39 min at midpoint).
|
||||
# Step 2 — FIRST SCHEDULED BREAK at cast 550 (the interval since cast 0):
|
||||
# take-break 45-120 s (a13). Resume casting at cast 551. The break fired on
|
||||
# the CAST COUNT, not on any bank visit.
|
||||
# Step 3 — casts #551..#901: countdown candidate 1,000-901 = 99 < 100
|
||||
# (restock_threshold) and nature 99 < 100 simultaneously (worst case 1:1) ->
|
||||
# the transition fires at the end of cast #901: FIRST RESTOCK at cast 901.
|
||||
# Deposit 901 x 180 = 162,180 gp (a10); the bank holds 0 supplies (all sales
|
||||
# were GE buys), so the fast path yields nothing -> open GE (a2), RE-BUY the
|
||||
# deficit 901 candidate + 901 nature (a11, live low + 5 %), collect (a12) ->
|
||||
# inventory back to 1,000/1,000. Batch net: -100,912 gp (live-low fills) or
|
||||
# -114,067 gp (max fills). The cast counter (901) and break counter continue.
|
||||
# Step 4 — SECOND BREAK at cast 1,100: the interval since break #1 is exactly
|
||||
# 550 casts (1,100 - 550); the cast-901 restock did NOT reset or shift it.
|
||||
# Step 5 — THIRD BREAK at cast 1,650 (1,100 + 550); SECOND RESTOCK at cast
|
||||
# 1,802 (901-cadence, 1,802 = 901 x 2). The sequences 550/1,100/1,650/2,200
|
||||
# and 901/1,802/2,703 interleave independently.
|
||||
# Step 6 — continue until a stop_condition fires: Magic 55 (the LA -> HLA
|
||||
# handoff — level 54 CONTINUES casting), the 2 h session horizon, the
|
||||
# capital stops (assets floor 311,600 or initial capital - total assets >
|
||||
# 684,400), 3 failed casts, or 3 consecutive no-fill GE rounds.
|
||||
# ============================================================================================
|
||||
|
||||
risk:
|
||||
ban_level: low
|
||||
notes:
|
||||
- "High cast cadence is the main detection vector; keep anti_ban delays."
|
||||
- "GE buy bursts: pace offers, respect the 4h limit window."
|
||||
- "High cast cadence is the main detection vector; keep the mandatory anti_ban delays (cadence pin: additive post-cast sleep [1.6, 3.4]s; session-realized ~742 casts/hr midpoint incl. startup + restock + breaks over a 2 h session; steady-state ~791; loop-only 837 is a ceiling reference, never the output)."
|
||||
- "Breaks are CAST-COUNT-based (every [400, 700] completed casts, 45-120s AFK) and independent of bank visits — never treat a restock trip as a break, and never reset the break counter on restock (gcd(550, 901) = 1)."
|
||||
- "GE buy bursts: pace offers, respect the 4h limit window (18,000 necklaces / 18,000 natures); offers persist until filled or aborted and a 4h limit reset is NOT an offer expiry."
|
||||
|
||||
# --- recovery block (owner guidance 2026-08-28: every activity must cover its complete runnable lifecycle) ---
|
||||
# - Missing materials / depleted supplies: the restock_threshold transition (casting ->
|
||||
# bank_supplies at candidate OR nature < 100) catches both mid-run depletions; the
|
||||
# restock phase (a9 -> a2 -> a10 -> a11) rebuilds to carried_batch and the loop
|
||||
# resumes (worked example steps 3-4). The entry NEVER withdraws a batch that was
|
||||
# never purchased — every restock re-buys the deficit at the GE.
|
||||
# - GE offers: partial fills are collected (a6/a11) and the remainder is re-placed at
|
||||
# the current edge (a3/a4/a5/a10); after 3 consecutive no-fill rounds (initial or
|
||||
# restock) the run stops (failed) — never sit in an unfillable offer loop. Unfilled
|
||||
# offers at session end are left resting by design (float reserve; coins return when
|
||||
# they fill or the operator aborts them — the single operator-touch point).
|
||||
# - Staff of fire cannot be equipped (a7): bounded retries (3), then FAIL CLOSED —
|
||||
# log ERROR + alert + stop. No fire-rune fallback is modeled (it would need its own
|
||||
# purchase/supply/rate path; the owner decision rejects a prose-only fallback).
|
||||
# - Invalid loadout (wrong item in hand / spell unavailable / carried counts below
|
||||
# carried_batch): re-run build-loadout (a8); a verified shortfall the bank does
|
||||
# not hold goes to bank_supplies; 3 consecutive failed casts -> failed.
|
||||
# - Capital: the stop checks TOTAL ASSETS (cash + supplies at current buy cost), and
|
||||
# both capital stops are assets-based (see stop_conditions) — cash converted into
|
||||
# supplies is not a loss and never fires a stop by itself.
|
||||
# - Explicit completion/stop: stop_conditions above (Magic 55 LA -> HLA handoff,
|
||||
# 2 h session horizon, assets floor 311,600, loss reserve 684,400, repeated
|
||||
# failures, fail-closed staff equip).
|
||||
|
||||
sources:
|
||||
- "OSRS wiki — Low Level Alchemy (level 21, 31 xp/cast, 3-tick, F2P; infobox 2026-08-27)"
|
||||
- "prices.runescape.wiki mapping (id 1654 gold necklace: members=false, limit 18000, lowalch 180, highalch 270, value 450; id 561 nature rune; id 554 fire rune)"
|
||||
- "prices.runescape.wiki latest 2026-08-27 (necklace buy 148, nature buy 144, fire buy 5)"
|
||||
verified: "2026-08-27" # keep quoted (YAML 1.1 date parsing)
|
||||
- "OSRS wiki — Grand Exchange (offers persist until filled or aborted; filled items and coin refunds are collected from the booth/collection box; partial fills are separately collectable) — verified 2026-08-28"
|
||||
- "OSRS wiki — Grand Exchange/Buying limits (4-hour window; the limit resets 4 hours after the FIRST unit is bought; outstanding offers remain active and a limit reset is NOT an offer expiry) — verified 2026-08-28"
|
||||
- "OSRS wiki — Staff of fire (page verified 2026-08-28 for the equip requirement: id 1387, F2P item, tradeable, options Wield — NO requirements row in the Infobox Item and NO requirement statement in the prose; contrast Battlestaff, whose prose states 'requires 30 Attack and 30 Magic to wield')"
|
||||
- "docs/schema.md run_control (iteration unit; break.every counts iterations) + docs/action-grammar.md:135 (anti_ban.delay = additive post-action sleep) + verbs ge_open/ge_buy/ge_collect/ge_offers_done (separate GE primitives) — the cadence + break + GE + lifecycle model; owner guidance 2026-08-28 (rate_model, fail-closed staff, monotonic counters); governor comment 10394 (build-loadout verified action, sign-corrected loss stop, 55 handoff boundary, fill-scenario GP bounds)"
|
||||
verified: "2026-08-27" # keep quoted (YAML 1.1 date parsing); prices last re-fetched live 2026-08-27
|
||||
|
||||
related:
|
||||
- magic-alch-handoff
|
||||
- high-alch-p2p
|
||||
- f2p-alch-catalog
|
||||
- mule-topup
|
||||
|
||||
652
codex/training/magic-alch-handoff.yaml
Normal file
652
codex/training/magic-alch-handoff.yaml
Normal file
@ -0,0 +1,652 @@
|
||||
id: magic-alch-handoff
|
||||
title: Magic training via alchemy (LA → SII → HLA handoff)
|
||||
domain: training
|
||||
tags: [magic-training, alching, f2p, xp-training]
|
||||
status: verified
|
||||
version: 5 # 5: bounce-fix 7 2026-08-29 (governor comment 10477, PR #10) — EXECUTABLE tier boundary: every tier predicate is mutually exclusive — SII only while 43 <= Magic < 55, HLA only when Magic >= 55 AND the session target is above 55, LA below 43 or the explicit SII-skip path in 43-54, completion FIRST when the configured target is reached (no Magic level can match two tiers; the old "43-55" SII window overlapped HLA at exactly 55). 4: bounce-fix 6 2026-08-28 (governor comment 10394) — build-loadout a7 VERIFIES collected staff/supplies and PROVES carried counts before the first cast (ready/ready->cast strengthened), capital-loss stop sign corrected (initial capital - total assets > 690,075). 3: bounce-fix 4 2026-08-28 (owner guidance 10331) — explicit rate_model discriminator (derived per-entry lifecycle rates), per-recipe inventory capacity floor(27/qty) with derived min/mid/max rates pinned in recipes.rates, complete GE acquisition path (open -> fill -> collect) for initial buy AND every restock (bank-stock fast path), fail-closed staff equip (bounded retries, no fire-rune fallback), configurable session target (55 = LA/SII->HLA handoff completion; >55 = executable HLA tier to the target; LA stays the 43-54 fallback), capital model (cash vs supplies, max-fill costs, reserve, assets-based stops)
|
||||
updated: "2026-08-28" # ISO dates must stay quoted — YAML 1.1 parses bare dates to datetime.date
|
||||
|
||||
summary: >
|
||||
The standard F2P alchemy training path: Low Level Alchemy from level 21
|
||||
(31 xp/cast), an optional Superheat Item window from 43 (53 xp/cast, smelts
|
||||
ore into bars), then High Level Alchemy from 55 (65 xp/cast, the wiki's
|
||||
recommended end-state). All three spells are F2P and stay castable after
|
||||
their unlock levels, so the handoffs are efficiency recommendations, not
|
||||
hard caps. The SESSION TARGET is configurable: the default 55 completes at
|
||||
the LA/SII -> HLA handoff; a target above 55 transitions into the
|
||||
executable HLA tier and continues until the target — HLA is never
|
||||
declared-but-unreachable, and Low Alchemy remains the executable fallback
|
||||
throughout Magic 43-54 whenever SII is skipped. SII model (owner guidance
|
||||
2026-08-28): a dynamic recipe table governed by the account's Smithing
|
||||
level — the highest UNLOCKED recipe whose complete recipe cost (ALL inputs
|
||||
at ALLOWED fill prices, live low + 5%) plus one nature rune stays under the
|
||||
bar's live GE price is selected; its primary ore (target_input, never coal)
|
||||
is the spell target; materials unobtainable -> next lower unlocked recipe,
|
||||
else skip SII and stay on LA. SII inventory cycles are CAPACITY-DERIVED:
|
||||
floor(27 / total input qty) casts per bank cycle (bronze 13, iron/silver/
|
||||
gold 27, steel 9, mithril 5, adamantite 3, runite 3) — never a fixed pack.
|
||||
Rates are SESSION-REALIZED under the declared rate_model: cast cycle +
|
||||
mandatory additive delays + breaks + banking + startup over a 2 h horizon
|
||||
(anchors: LA 23,000 / SII steel 12,400 / HLA 48,200 Magic XP/hr; per-recipe
|
||||
min/mid/max rates pinned in the recipes table and enforced by the
|
||||
validator). Every purchase follows the complete GE path open -> place ->
|
||||
fill/wait -> collect, for the initial acquisition and every restock (bank
|
||||
fast path only when the bank holds stock). Staff-of-fire equip failure is
|
||||
FAIL-CLOSED (bounded retries, then log ERROR + alert + stop).
|
||||
|
||||
accounts:
|
||||
membership: f2p # LA, SII and HLA are all members=No spells
|
||||
min_level: 21 # Magic 21 — Low Level Alchemy unlock
|
||||
requires_quest: []
|
||||
requires_other:
|
||||
- "Staff of Fire equipped (drops LA/SII/HLA rune cost to 1 nature rune per cast; NO level requirement documented on the OSRS wiki — verified 2026-08-28, see sources). Equip failure is FAIL-CLOSED: bounded retries (3), then log ERROR + alert + stop — there is no fire-rune fallback in this model"
|
||||
- "SII tier requires the selected recipe's Smithing level (recipes table: bronze 1 / iron 15 / silver 20 / steel 30 / gold 40 / mithril 50 / adamantite 70 / runite 85) — the highest UNLOCKED recipe is selected and an unmet gate is NEVER selected (selection.mode)"
|
||||
- "Starting capital >= ~1.31M gp CASH for the LA/HLA tier path (staff hard cap 5,000 + first batch 1,000/1,000 at MAX allowed fill 307,650 + session loss reserve 690,075 = 6 worst-case 901-cast batches at live-low+5% fills (covers Magic 21 -> 55) + resting-offer float 307,650). The SII window uses capacity-sized packs (steel example: 9 x (1 iron 105 + 2 coal 157.5 + 1 nature 152.25) = 5,150 gp per pack at max fill). The capital stop checks TOTAL ASSETS (cash + supplies at current buy cost), never raw cash — cash legitimately converts into supplies"
|
||||
- "Session target Magic level configured at session start: default 55 (completes at the LA/SII -> HLA handoff); a target above 55 runs the HLA tier until the target; LA remains the executable fallback throughout 43-54 when SII is skipped"
|
||||
- "A bank with GE access within reach (alch spot = the bank booth; restock trips [60, 120] s)"
|
||||
|
||||
best_practice:
|
||||
equipment:
|
||||
- item: staff of fire
|
||||
why: "unlimited fire runes — the rune cost of every alchemy spell drops to a single nature rune per cast; equip requirement: none documented on the OSRS wiki (verified 2026-08-28); if it cannot be equipped after bounded retries the run FAILS CLOSED (no fallback modeled)"
|
||||
source: "OSRS wiki — High Level Alchemy (rune cost table); OSRS wiki — Staff of fire (id 1387: no requirements row in the infobox, none in the prose — contrast Battlestaff 'requires 30 Attack and 30 Magic')"
|
||||
techniques:
|
||||
- name: hand off LA -> HLA at level 55 (configurable target)
|
||||
why: "LA page: 'Players with level 55 Magic are generally recommended to use High Level Alchemy instead, as it provides more coins and experience per cast' — 65 vs 31 xp/cast, 60% vs 40% of item value. The default session target is 55; a target above 55 keeps casting HLA (65 xp/cast) until the configured level — the HLA tier is never declared but unreachable"
|
||||
source: "OSRS wiki — Low Level Alchemy (Comparison with High Level Alchemy); High Level Alchemy (infobox: level 55, 65 xp)"
|
||||
- name: optional Superheat Item window 43-54 (43 <= Magic < 55)
|
||||
why: "SII unlocks at 43 (53 xp/cast) and smelts ore into bars without a furnace — a training window that can profit when ore/bar margins are positive; it cannot be cast on noted ore, so it needs the exact recipe inputs in inventory rather than a note stack. The inventory holds floor(27 / total input qty) casts per bank cycle (steel = 9) — never a fixed 24-cast pack"
|
||||
source: "OSRS wiki — Superheat Item (43 Magic, 53 xp, F2P; 'smelt ore into bars without a furnace'; 'cannot be cast on noted ore')"
|
||||
- name: select the highest UNLOCKED SII recipe, never an unmet gate
|
||||
why: "at each cast the active recipe = the recipes-table entry with the highest smithing_level <= current Smithing whose complete input cost (ALL inputs at ALLOWED fill prices = live low + 5%) + one nature rune at allowed fill stays under the bar's live GE price; the spell targets that recipe's declared target_input (the primary ore — never coal); when the selected recipe's materials cannot be obtained, fall back to the next lower unlocked recipe; when none has a positive margin, skip SII and stay on LA (LA is executable throughout 43-54)"
|
||||
source: "OSRS wiki — Superheat Item (requires the Smithing level and materials of the bar); Smithing (bar smelting table); prices.runescape.wiki (live GE prices); owner guidance 2026-08-28 (selection.mode, allowed-fill eligibility)"
|
||||
- name: buy GE items below alch value, cast on noted items at a bank
|
||||
why: "HLA page: 'Players who train this way can break even on the cost of runes, or even turn a profit, by buying items on the Grand Exchange for a lower cost than the item's High Alchemy value'; all alchemy spells work on noted items, saving bank withdrawals per cast"
|
||||
source: "OSRS wiki — High Level Alchemy (GE buying for break-even/profit; noted-item casting)"
|
||||
- name: treat the handoffs as soft efficiency choices
|
||||
why: "all three spells remain castable past 21/43/55 and stay on the standard F2P spellbook, so the tier switches optimise xp/cast and cost rather than gate the path; LA is the executable fallback whenever the SII window is skipped"
|
||||
source: "OSRS wiki — Low Level Alchemy; Superheat Item; High Level Alchemy (level + experience infoboxes, members=No)"
|
||||
|
||||
economy:
|
||||
# Per-cast economics at 2026-08-27 snapshot (prices.runescape.wiki latest):
|
||||
# staff of fire -> 1 nature rune per cast. Nature rune id 561 buy 145
|
||||
# (mapping limit 18000, cross-checked against Module:Exchange/Nature_rune,
|
||||
# members=false, lowalch 72 = 40% of value 180 — consistency assertion).
|
||||
# Income/net per cast depend on the alched item or the recipe bar, so they
|
||||
# live in the per-activity entries and in the recipes table (this entry
|
||||
# prices the shared consumable + the rate model).
|
||||
# xp_per_hour pins the rate_model ANCHOR tier (sii, steel-bar): the entry's
|
||||
# own declared lifecycle — no hard-coded per-activity constants.
|
||||
item: nature rune
|
||||
item_id: 561
|
||||
cost_per_cycle: 145 # one nature rune per cast (staff of fire), buy price 2026-08-27
|
||||
xp_per_hour: 12400 # SII anchor, SESSION-REALIZED: steel mid 249.1 casts/hr x 53 x startup factor 0.9375 = 12,379 (pin 12,400)
|
||||
# ---- rate model (derived from rate_model + actions + run_control + recipes;
|
||||
# enforced by the validator's rate_model_errors gate) ----
|
||||
# Cast: 1.8s (3 ticks x 0.6s, rate_model.cast_ticks) + anti_ban.delay
|
||||
# [1.6, 3.4]s ADDITIVE (action-grammar.md:135) = 3.4-5.2s, midpoint 4.3s.
|
||||
# Restock trip [60, 120]s (rate_model.restock_trip_s); breaks every
|
||||
# [400, 700] casts for [45, 120]s (run_control.break) -> amortised break
|
||||
# share 45/700 fast, 82.5/550 mid, 120/400 slow.
|
||||
# ALCH tiers (LA/HLA): 901-cast restock batch (carried_batch 1,000 -
|
||||
# restock_threshold 100), steady-state 1,019.7 / 791.3 / 639.2 casts/hr;
|
||||
# SESSION-REALIZED over the 2 h horizon with startup 300-600s (factor
|
||||
# 0.9583/0.9375/0.9167): 977.1 / 741.8 / 585.9 casts/hr ->
|
||||
# LA 23,000 xp/hr = 31 x 741.8 (22,995)
|
||||
# HLA 48,200 xp/hr = 65 x 741.8 (48,217)
|
||||
# SII tiers: per-recipe capacity = floor(27 / total input qty) (steel 9,
|
||||
# bronze 13, iron/silver/gold 27, mithril 5, adamantite/runite 3); full
|
||||
# derived min/mid/max rates live in each recipe's rates block (validator-
|
||||
# checked): steel steady mid 249.1 casts/hr = 13,204 Magic XP/hr; the
|
||||
# xp_per_hour anchor adds the startup factor (0.9375 mid) -> 12,400.
|
||||
# Superseded figures (all fail the derived gate on purpose): loop-only
|
||||
# 837 casts/hr; the 8-14-cast-break regime (~305 casts/hr); the 1,400/
|
||||
# 1,800-cast regimes; the impossible 24-cast SII pack (518.0 casts/hr) —
|
||||
# capacity is floor(27/qty), never a fixed pack.
|
||||
supplies:
|
||||
- item: nature rune
|
||||
qty_per_cycle: 1
|
||||
source: ge
|
||||
ge_limit: 18000 # mapping + Module:Exchange agree
|
||||
profit_drivers:
|
||||
- "XP per cast by tier (wiki infoboxes): LA 31 (level 21) / SII 53 (level 43) / HLA 65 (level 55); SII also grants the bar's Smithing XP (recipes table)"
|
||||
- "HLA can break even or profit on GE-bought items priced below their High Alchemy value (HLA page); LA is a loss at current prices (see low-alch-f2p)"
|
||||
- "SII turns a profit only when the complete recipe cost (ALL inputs at ALLOWED fill prices + one nature rune at allowed fill) stays under the resulting bar's GE price — re-check margins per window and select the highest UNLOCKED recipe with a positive margin; never a steel-only default, never an unmet Smithing gate"
|
||||
|
||||
# Selection model (owner guidance 2026-08-28): the Superheat recipe is chosen
|
||||
# at runtime from the recipes table — never hardcoded to one bar, never above
|
||||
# the account's Smithing level, with a deterministic fallback chain. The
|
||||
# validator proves eligibility (smithing gate + complete-recipe margin),
|
||||
# target_input (declared input, never coal), unique gates, and the fallback
|
||||
# path via its fixtures.
|
||||
selection:
|
||||
mode: highest-unlocked
|
||||
eligible_rule: "at each cast, the active recipe = the recipes-table entry with the highest smithing_level <= current Smithing level whose complete input cost at ALLOWED fill prices (every input at live GE low + 5%, the a4 max_price cap) + one nature rune at allowed fill < the bar's live GE price — the full actual/allowed recipe cost, not a headline ore price"
|
||||
fallback: "when the selected recipe's materials cannot be obtained (3 consecutive failed GE purchases / unfillable offers), drop to the next lower unlocked recipe and re-check its allowed-fill margin; when no unlocked recipe has a positive margin, skip SII for this window and stay on LA throughout 43-54 — LA remains executable (a8 handles level < 43 AND the 43-54 SII-skip window); never select a recipe whose Smithing requirement is unmet, never cast on coal"
|
||||
|
||||
# Concrete F2P bar recipes for Superheat Item. SII requires the bar's
|
||||
# Smithing level and its exact materials, so every selectable bar is modelled
|
||||
# with ALL inputs and quantities (id 453 coal appears in steel/mithril/
|
||||
# adamantite/runite). Levels, xp and item ids from the OSRS wiki (Smithing
|
||||
# smelting table; Superheat Item grants the bar's Smithing XP per cast).
|
||||
# target_input = the PRIMARY ORE the spell is cast on (a declared input,
|
||||
# never coal — the validator enforces both).
|
||||
# rates (validator-checked, derived from the entry's rate_model): capacity =
|
||||
# floor(27 / total input qty) casts per bank cycle (28-slot inventory minus
|
||||
# the nature stack); casts_per_hour and magic_xp_per_hour are the STEADY-
|
||||
# STATE min/mid/max (cycle endpoints 3.4/4.3/5.2s, trip 60/90/120s,
|
||||
# break share 45/700, 82.5/550, 120/400). The economy.xp_per_hour anchor
|
||||
# adds the startup factor (see rate_model).
|
||||
# econ 2026-08-27: bar margin = bar GE price - (all inputs at allowed fill +
|
||||
# one nature rune at allowed fill); the client selects via selection.mode.
|
||||
recipes:
|
||||
bronze-bar:
|
||||
bar: Bronze bar
|
||||
bar_item_id: 2349
|
||||
smithing_level: 1
|
||||
smithing_xp: 6.2
|
||||
target_input: Copper ore
|
||||
inputs:
|
||||
- item: Copper ore
|
||||
item_id: 436
|
||||
qty: 1
|
||||
source: ge
|
||||
- item: Tin ore
|
||||
item_id: 438
|
||||
qty: 1
|
||||
source: ge
|
||||
rates:
|
||||
capacity: 13
|
||||
casts_per_hour: {min: 445.6, mid: 316.5, max: 244.4}
|
||||
magic_xp_per_hour: {min: 23617, mid: 16776, max: 12952}
|
||||
iron-bar:
|
||||
bar: Iron bar
|
||||
bar_item_id: 2351
|
||||
smithing_level: 15
|
||||
smithing_xp: 12.5
|
||||
target_input: Iron ore
|
||||
inputs:
|
||||
- item: Iron ore
|
||||
item_id: 440
|
||||
qty: 1
|
||||
source: ge
|
||||
rates:
|
||||
capacity: 27
|
||||
casts_per_hour: {min: 633.1, mid: 462.5, max: 362.0}
|
||||
magic_xp_per_hour: {min: 33554, mid: 24514, max: 19187}
|
||||
silver-bar:
|
||||
bar: Silver bar
|
||||
bar_item_id: 2355
|
||||
smithing_level: 20
|
||||
smithing_xp: 13.7
|
||||
target_input: Silver ore
|
||||
inputs:
|
||||
- item: Silver ore
|
||||
item_id: 442
|
||||
qty: 1
|
||||
source: ge
|
||||
rates:
|
||||
capacity: 27
|
||||
casts_per_hour: {min: 633.1, mid: 462.5, max: 362.0}
|
||||
magic_xp_per_hour: {min: 33554, mid: 24514, max: 19187}
|
||||
steel-bar:
|
||||
bar: Steel bar
|
||||
bar_item_id: 2353
|
||||
smithing_level: 30
|
||||
smithing_xp: 17.5
|
||||
target_input: Iron ore
|
||||
inputs:
|
||||
- item: Iron ore
|
||||
item_id: 440
|
||||
qty: 1
|
||||
source: ge
|
||||
- item: Coal
|
||||
item_id: 453
|
||||
qty: 2
|
||||
source: ge
|
||||
rates:
|
||||
capacity: 9
|
||||
casts_per_hour: {min: 355.3, mid: 249.1, max: 191.2}
|
||||
magic_xp_per_hour: {min: 18833, mid: 13204, max: 10131}
|
||||
gold-bar:
|
||||
bar: Gold bar
|
||||
bar_item_id: 2357
|
||||
smithing_level: 40
|
||||
smithing_xp: 22.5
|
||||
target_input: Gold ore
|
||||
inputs:
|
||||
- item: Gold ore
|
||||
item_id: 444
|
||||
qty: 1
|
||||
source: ge
|
||||
rates:
|
||||
capacity: 27
|
||||
casts_per_hour: {min: 633.1, mid: 462.5, max: 362.0}
|
||||
magic_xp_per_hour: {min: 33554, mid: 24514, max: 19187}
|
||||
mithril-bar:
|
||||
bar: Mithril bar
|
||||
bar_item_id: 2359
|
||||
smithing_level: 50
|
||||
smithing_xp: 30
|
||||
target_input: Mithril ore
|
||||
inputs:
|
||||
- item: Mithril ore
|
||||
item_id: 447
|
||||
qty: 1
|
||||
source: ge
|
||||
- item: Coal
|
||||
item_id: 453
|
||||
qty: 4
|
||||
source: ge
|
||||
rates:
|
||||
capacity: 5
|
||||
casts_per_hour: {min: 232.8, mid: 160.4, max: 122.0}
|
||||
magic_xp_per_hour: {min: 12338, mid: 8499, max: 6468}
|
||||
adamantite-bar:
|
||||
bar: Adamantite bar
|
||||
bar_item_id: 2361
|
||||
smithing_level: 70
|
||||
smithing_xp: 37.5
|
||||
target_input: Adamantite ore
|
||||
inputs:
|
||||
- item: Adamantite ore
|
||||
item_id: 449
|
||||
qty: 1
|
||||
source: ge
|
||||
- item: Coal
|
||||
item_id: 453
|
||||
qty: 6
|
||||
source: ge
|
||||
rates:
|
||||
capacity: 3
|
||||
casts_per_hour: {min: 153.4, mid: 104.5, max: 79.1}
|
||||
magic_xp_per_hour: {min: 8131, mid: 5538, max: 4194}
|
||||
runite-bar:
|
||||
bar: Runite bar
|
||||
bar_item_id: 2363
|
||||
smithing_level: 85
|
||||
smithing_xp: 50
|
||||
target_input: Runite ore
|
||||
inputs:
|
||||
- item: Runite ore
|
||||
item_id: 451
|
||||
qty: 1
|
||||
source: ge
|
||||
- item: Coal
|
||||
item_id: 453
|
||||
qty: 8
|
||||
source: ge
|
||||
rates:
|
||||
capacity: 3
|
||||
casts_per_hour: {min: 153.4, mid: 104.5, max: 79.1}
|
||||
magic_xp_per_hour: {min: 8131, mid: 5538, max: 4194}
|
||||
|
||||
# Explicit activity/rate discriminator (owner guidance 2026-08-28, bounce 4):
|
||||
# this entry OPTS IN to the derived-rate gate; every rate below derives from
|
||||
# the entry's own declared lifecycle, and the validator re-derives it.
|
||||
rate_model:
|
||||
anchor_tier: sii # xp_per_hour pins the SII tier's realized rate
|
||||
anchor_recipe: steel-bar # the anchor recipe (must be a declared recipe)
|
||||
cast_ticks: 3 # LA/SII/HLA are 3-tick casts -> 1.8 s (0.6 s/tick)
|
||||
restock_trip_s: [60, 120] # GE-adjacent booth trip per restock
|
||||
session_horizon_s: 7200 # 2 h session; startup is amortised over it
|
||||
startup_s: [300, 600] # one-time GE acquisition + loadout
|
||||
alch_carry_batch: 1000 # LA/HLA tier: stacked candidates + natures
|
||||
alch_restock_threshold: 100 # -> 901-cast LA/HLA restock cadence
|
||||
sii_capacity_slots: 27 # 28-slot inventory minus the nature stack
|
||||
|
||||
state_machine:
|
||||
initial: idle
|
||||
terminal: [complete, failed]
|
||||
states:
|
||||
idle:
|
||||
goal: "session start at the GE bank booth; choose the session Magic target (default 55 — completes at the LA/SII -> HLA handoff; above 55 the HLA tier runs to the target). Open GE (a2), place the initial offers (staff a3, tier supplies a4), record initial capital in the cash ledger (total assets = cash + supplies at current buy cost). Nothing is bought or collected without an open GE interface"
|
||||
next: [wait_offers, complete, failed]
|
||||
wait_offers:
|
||||
goal: "wait for the pending offers (ge_offers_done); when filled, collect every purchase + refund from the collection box (a5 — never leave purchases in the box). PARTIAL FILLS: collect the filled portion, re-place the remainder at the current edge (a3/a4); 3 consecutive no-fill rounds -> failed. An offer still unfilled at session end is left resting by design — its coins are tied up (float reserve) and return when it fills or the operator aborts it (the single operator-touch point)"
|
||||
next: [ready, wait_offers, failed]
|
||||
ready:
|
||||
goal: "equip the staff of fire (a6 — bounded retries, then FAIL CLOSED) and build the VERIFIED loadout (a7 build-loadout): verify the collected staff + tier supplies (from a5), deposit overflow, withdraw only the real bank-stock shortfall, and PROVE the carried counts equal the tier's carried amounts BEFORE the first cast (a8/a9)"
|
||||
next: [cast, bank_supplies, failed]
|
||||
cast:
|
||||
goal: "cast the active tier spell with the tier-correct target — LA (< 43, or 43-54 when SII is skipped) or HLA (>= 55, only when the session target is above 55) on a noted alch candidate (a8); SII (43 <= Magic < 55, selection.mode) on the selected recipe's declared target_input (primary ore, never coal) with its exact allowed-fill inputs withdrawn (a9). The tier predicates are MUTUALLY EXCLUSIVE: at any Magic level exactly one tier is selectable — SII only while 43 <= Magic < 55, HLA only when Magic >= 55 and the target is higher, completion FIRST when the target is reached (no level can match two tiers; the old '43-55' SII window overlapped HLA at exactly 55). A break fires on the completed-cast counter (a13), NEVER on bank visits, and restocking never resets it"
|
||||
next: [cast, bank_supplies, complete, failed]
|
||||
bank_supplies:
|
||||
goal: "restock to the tier's carried amounts: deposit coins + smelted bars and withdraw ALL tier supplies the bank holds (a10 — bank-stock fast path only when the bank actually holds enough); for the remaining deficit, open GE (a2), buy the deficit (a11, live low + 5%), collect it (a12) — never withdraw a batch that was never purchased. Restocking never resets the cast or break counters"
|
||||
next: [cast, bank_supplies, failed]
|
||||
complete:
|
||||
goal: "magic level >= the configured session target (default 55 — completes at the LA/SII -> HLA handoff; a target above 55 finishes only after the executable HLA tier reaches it)"
|
||||
failed:
|
||||
goal: "hard failure — stop, log ERROR sentinel, alert"
|
||||
transitions:
|
||||
- from: idle
|
||||
when: "staff + tier supply offers all placed (a3/a4)"
|
||||
to: wait_offers
|
||||
- from: idle
|
||||
when: "magic level >= session target at session start"
|
||||
to: complete
|
||||
- from: idle
|
||||
when: "3 consecutive offer-place failures at session start (no fallback candidate/recipe)"
|
||||
to: failed
|
||||
- from: wait_offers
|
||||
when: "ge_offers_done AND all purchases collected (a5)"
|
||||
to: ready
|
||||
- from: wait_offers
|
||||
when: "partial fill: filled portion collected (a5), remainder re-placed at the current edge (a3/a4) — still waiting"
|
||||
to: wait_offers
|
||||
- from: wait_offers
|
||||
when: "3 consecutive no-fill rounds (offer cannot fill at the accepted edge)"
|
||||
to: failed
|
||||
- from: ready
|
||||
when: "staff equipped (a6) AND build-loadout verified the carried counts at the tier's carried amounts (a7 — collected staff/supplies present, overflow deposited, only a real bank-stock shortfall withdrawn; carried counts PROVEN)"
|
||||
to: cast
|
||||
- from: ready
|
||||
when: "staff equip failed after bounded retries — FAIL CLOSED"
|
||||
to: failed
|
||||
- from: ready
|
||||
when: "build-loadout verification shows a carried shortfall the bank does not hold — restock first"
|
||||
to: bank_supplies
|
||||
- from: cast
|
||||
when: "level < 43, or (43 <= level < 55 with SII skipped) — LA tier: cast on the cheapest alch candidate (LA is executable below 43 and throughout the 43-54 window only when a recipe-margin issue explicitly skips SII; at Magic 55+ the LA predicate is never true — no level matches two tiers)"
|
||||
to: cast
|
||||
- from: cast
|
||||
when: "43 <= level < 55 and the SII window is chosen (MUTUALLY EXCLUSIVE with HLA — SII is selectable ONLY below 55, never at 55+) — selection.mode picks the recipes-table entry with the highest smithing_level <= current Smithing and a positive allowed-fill complete-cost margin; cast on its target_input"
|
||||
to: cast
|
||||
- from: cast
|
||||
when: "43 <= level < 55 — SII fallback: the selected recipe's materials cannot be obtained, so drop to the next lower unlocked recipe (never an unmet Smithing gate) and continue SII if its margin is positive"
|
||||
to: cast
|
||||
- from: cast
|
||||
when: "43 <= level < 55 and no unlocked recipe has a positive margin this window — skip SII and stay on LA"
|
||||
to: cast
|
||||
- from: cast
|
||||
when: "level >= 55 and session target > 55 — the HLA tier executes (a8) until magic reaches the target (MUTUALLY EXCLUSIVE: HLA is selectable only when the target is ABOVE 55, so an account at 55 with target 55 completes first rather than matching SII/HLA)"
|
||||
to: cast
|
||||
- from: cast
|
||||
when: "LA/HLA tier: candidate count < restock_threshold (100) OR nature count < restock_threshold (100); SII tier: bars_in_inventory >= the selected recipe's capacity (floor(27 / total input qty): steel 9, bronze 13, mithril 5, ...) OR any selected-recipe input < 1 — deterministic restock triggers, pinned numbers"
|
||||
to: bank_supplies
|
||||
- from: cast
|
||||
when: "magic level >= session target (default 55 — completes at the LA/SII -> HLA handoff; targets above 55 require the executable HLA tier FIRST — completion is evaluated before tier selection, so the configured target always wins over any remaining tier predicate)"
|
||||
to: complete
|
||||
- from: cast
|
||||
when: "3 consecutive failed casts (client issue — do not loop)"
|
||||
to: failed
|
||||
- from: bank_supplies
|
||||
when: "restocked to the tier's carried amounts (bank fast path or re-bought deficit collected)"
|
||||
to: cast
|
||||
- from: bank_supplies
|
||||
when: "restock partial: deficit re-bought but offers still filling (ge_offers_done false) — loop the restock phase"
|
||||
to: bank_supplies
|
||||
- from: bank_supplies
|
||||
when: "3 consecutive no-fill restock rounds OR a capital stop fires (assets / loss-reserve checks in stop_conditions)"
|
||||
to: failed
|
||||
|
||||
actions:
|
||||
- id: a1
|
||||
step: reach-bank
|
||||
verb: move_to
|
||||
target: bank
|
||||
params:
|
||||
location: "GE-adjacent bank (alch spot = the bank booth, so restock is a single short leg, 60-120s)"
|
||||
method: [teleport, walk]
|
||||
on_fail: retry
|
||||
anti_ban:
|
||||
delay: [400, 1600]
|
||||
|
||||
- id: a2
|
||||
step: open-ge
|
||||
verb: ge_open
|
||||
target: grand-exchange
|
||||
params:
|
||||
note: "open the GE interface at the booth. The entry NEVER buys (a3/a4/a11) or collects (a5/a12) without an open GE interface — the action grammar defines ge_open, ge_buy, ge_collect as separate verbs, so the open step is explicit"
|
||||
on_fail: retry
|
||||
anti_ban:
|
||||
delay: [600, 1400]
|
||||
|
||||
- id: a3
|
||||
step: buy-staff
|
||||
verb: ge_buy
|
||||
target: grand-exchange
|
||||
params:
|
||||
item: "staff of fire"
|
||||
qty: 1
|
||||
max_price: "live low + 25 % (wiki value 1,500; hard cap 5,000)"
|
||||
note: "offer rests until filled or the run ends; on a partial/no fill, collect what filled (a5) and re-place the remainder at the current edge — bounded retries, then the run fails closed (no fire-rune fallback exists)"
|
||||
on_fail: retry
|
||||
anti_ban:
|
||||
delay: [1200, 3000]
|
||||
|
||||
- id: a4
|
||||
step: buy-supplies
|
||||
verb: ge_buy
|
||||
target: grand-exchange
|
||||
params:
|
||||
item: "nature runes + the tier's supplies — LA/HLA: the current least-loss alch candidate; SII: the exact unnoted inputs of the SELECTED recipe (every input and quantity from the recipes table, e.g. steel-bar = 1 iron ore + 2 coal), only while the allowed-fill complete-cost margin is positive"
|
||||
qty: "LA/HLA: carried_batch 1,000 (4h GE limits: natures 18,000, candidates per mapping); SII: one capacity-sized pack of the selected recipe — capacity = floor(27 / total input qty) casts (steel = 9, so 9 x each input quantity + 9 natures per pack)"
|
||||
max_price: "live low + 5 %"
|
||||
note: "offer rests until filled or the run ends; partial fills are collected (a5) and the remainder re-placed at the current edge; 3 consecutive no-fills -> SII recipe fallback, else failed"
|
||||
on_fail: retry
|
||||
anti_ban:
|
||||
delay: [1200, 3000]
|
||||
|
||||
- id: a5
|
||||
step: collect-purchases
|
||||
verb: ge_collect
|
||||
target: grand-exchange
|
||||
params:
|
||||
note: "collect every filled purchase and refund from the GE collection box into the inventory — staff, candidates/natures, or the recipe's exact inputs (and the equivalent on every restock). Partial offers: the collected portion is added to the ledger; nothing is left in the box at session start"
|
||||
on_fail: retry
|
||||
anti_ban:
|
||||
delay: [600, 1400]
|
||||
|
||||
- id: a6
|
||||
step: equip-staff
|
||||
verb: menu_option
|
||||
target: "staff of fire in inventory"
|
||||
params:
|
||||
option: "Wield"
|
||||
note: "Equip requirement is NONE documented on the OSRS wiki Staff of fire page (no requirements row in the infobox, none in the prose; compare Battlestaff 'requires 30 Attack and 30 Magic'; verified 2026-08-28). FAIL-CLOSED path: bounded retries (3), then log ERROR + alert + stop — no fire-rune fallback is modeled (never loop on equip attempts)"
|
||||
on_fail: retry
|
||||
anti_ban:
|
||||
delay: [600, 1800]
|
||||
|
||||
- id: a7
|
||||
step: build-loadout
|
||||
verb: bank_inventory
|
||||
target: bank
|
||||
params:
|
||||
deposit: [overflow products]
|
||||
withdraw: "to the tier's carried amounts (only the real bank-stock shortfall — collected purchases from a5 are already in the inventory): LA/HLA 1,000 candidate + 1,000 nature; SII one capacity-sized pack of the selected recipe (steel: 9 iron + 18 coal + 9 natures)"
|
||||
verify: "the collected staff of fire + tier supplies (a5) are present, and the carried counts EQUAL the tier's carried amounts — the loadout is PROVEN before the first cast (a8/a9); a verified shortfall the bank does not hold sends the slot to bank_supplies instead"
|
||||
on_fail: retry
|
||||
anti_ban:
|
||||
delay: [500, 1100]
|
||||
|
||||
- id: a8
|
||||
step: cast-alch
|
||||
verb: use_item_on
|
||||
target: "noted alch candidate in inventory (LA and HLA tiers)"
|
||||
params:
|
||||
spell: "Low Level Alchemy (level < 43, or 43-54 when SII is skipped) | High Level Alchemy (level >= 55 — only when the session target is above 55; HLA is never declared-but-unreachable; tier predicates are MUTUALLY EXCLUSIVE — SII only 43 <= Magic < 55, HLA only >= 55 with the target higher, completion first at the target)"
|
||||
item: "cheapest live alch candidate in inventory — LA/HLA are alchemy tiers, so the selection rule is the alch-candidate rule"
|
||||
on: "itself"
|
||||
on_fail: retry
|
||||
anti_ban:
|
||||
delay: [1600, 3400] # MANDATORY post-action sleep, ADDITIVE to the 1.8s cast (3 ticks x 0.6s; action-grammar.md:135): cycle = 3.4-5.2s, mid 4.3s -> LA/HLA session-realized ~742 casts/hr incl. startup + restock + breaks (rate_model)
|
||||
|
||||
- id: a9
|
||||
step: cast-superheat
|
||||
verb: use_item_on
|
||||
target: "the selected recipe's declared target_input in inventory (the primary ore — never coal; SII tier only, 43 <= Magic < 55)"
|
||||
params:
|
||||
spell: "Superheat Item"
|
||||
selected_recipe: "runtime selection per selection.mode: the recipes-table entry with the highest smithing_level <= current Smithing whose complete input cost at ALLOWED fill prices + one nature rune at allowed fill < the bar's live GE price; fall back to the next lower unlocked recipe when its materials cannot be obtained"
|
||||
target_input: "the selected recipe's declared target_input field (primary ore; coal can never be the spell target)"
|
||||
on: "itself"
|
||||
consumption: "1 x each recipe input (e.g. steel = 1 iron ore + 2 coal) + 1 nature per cast -> 1 bar, +53 Magic xp + the bar's Smithing xp; the pack holds capacity = floor(27 / total input qty) casts (steel = 9)"
|
||||
on_fail: skip # no unlocked positive-margin recipe -> skip SII, stay on LA (selection.fallback)
|
||||
anti_ban:
|
||||
delay: [1600, 3400] # post-action sleep (additive): same 3.4-5.2s/cast as a8; per-recipe realized rates in recipes.rates (steel mid 249.1 casts/hr steady, session anchor 12,400 xp/hr)
|
||||
|
||||
- id: a10
|
||||
step: restock-deposit
|
||||
verb: bank_inventory
|
||||
target: bank
|
||||
params:
|
||||
deposit: [all coins, all products] # products incl. smelted bars during SII
|
||||
withdraw: "ALL tier supplies currently in the bank, up to the carried amounts (LA/HLA 1,000/1,000; SII one capacity-sized pack of the selected recipe) — the bank-stock FAST PATH applies only when the bank actually holds enough; the remaining deficit is bought at the GE (a11) and collected (a12)"
|
||||
on_fail: alert
|
||||
anti_ban:
|
||||
delay: [500, 1100]
|
||||
|
||||
- id: a11
|
||||
step: restock-buy
|
||||
verb: ge_buy
|
||||
target: grand-exchange
|
||||
params:
|
||||
item: "the tier's supplies to top up to the carried amounts"
|
||||
qty: "deficit = carried amount - inventory count after the a10 fast path (LA/HLA: 901 candidate + 901 natures after a 901-cast batch with an empty bank; SII: the selected recipe's capacity-sized pack minus whatever the bank held)"
|
||||
max_price: "live low + 5 %"
|
||||
note: "the deficit is RE-BOUGHT at the GE on every restock — the entry never withdraws a batch that was never purchased; partial/failed fills use the same collect + re-place recovery as the initial acquisition"
|
||||
on_fail: retry
|
||||
anti_ban:
|
||||
delay: [1200, 3000]
|
||||
|
||||
- id: a12
|
||||
step: restock-collect
|
||||
verb: ge_collect
|
||||
target: grand-exchange
|
||||
params:
|
||||
note: "collect the re-bought deficit into the inventory — carried amounts are restored before casting resumes"
|
||||
on_fail: retry
|
||||
anti_ban:
|
||||
delay: [600, 1400]
|
||||
|
||||
- id: a13
|
||||
step: take-break
|
||||
verb: take_break
|
||||
target: "current location"
|
||||
params:
|
||||
duration: "[45, 120] seconds of idle AFK per break (matches run_control.break.for)"
|
||||
note: "executed by the translator when the completed-cast counter reaches run_control.break.every [400, 700] casts — this IS run_control.break's executor, fired on CAST COUNTS, not on bank visits; the cast counter is NOT reset by restocking (breaks land at 550/1,100/1,650 in the midpoint example, independent of the 901-cast alch / capacity-sized SII restock cadences)"
|
||||
on_fail: skip
|
||||
|
||||
run_control:
|
||||
iteration: "one cast" # schema.md: break.every counts iterations, so every
|
||||
# value below is in completed casts, NOT bank trips
|
||||
max_iterations: null
|
||||
break:
|
||||
every: [400, 700] # COMPLETED CASTS between AFK breaks (midpoint 550 = ~39 min
|
||||
# at the 4.3s midpoint cycle). Cast-count-based, independent of
|
||||
# banking; a restock trip NEVER counts as a break and does not
|
||||
# reset this counter (owner decision 2026-08-28)
|
||||
for: [45, 120] # seconds of idle AFK
|
||||
stop_conditions:
|
||||
- "magic level >= session target (default 55: completes at the LA/SII -> HLA handoff; when the configured target is above 55, the HLA tier executes from 55 until the target — HLA is never declared-but-unreachable)"
|
||||
- "session elapsed >= 2 h (session horizon — the rate model amortises startup over it)"
|
||||
- "total assets (cash + supplies at current buy cost) < the next tier batch at max fill plus staff replacement (LA/HLA: 312,650 = 307,650 + 5,000; SII steel: 10,150 = 5,150 + 5,000) — assets, NOT raw cash: cash that became supplies is not a loss"
|
||||
- "session net loss = initial capital - total assets > 690,075 — the 6-batch worst-case LA reserve (Magic 21 -> 55 at max fills) is exhausted (a loss is WHEN ASSETS FALL; total assets - initial capital goes NEGATIVE on losses and can never exceed the reserve — the reversed sign never fires)"
|
||||
- "3 consecutive failed casts (client issue — do not loop)"
|
||||
- "3 consecutive no-fill GE rounds (initial acquisition or restock) with no fallback recipe/candidate available"
|
||||
- "staff of fire equip failed after bounded retries — FAIL CLOSED (log ERROR, alert, stop)"
|
||||
|
||||
# ================= WORKED EXAMPLE (pinned, deterministic — owner guidance 2026-08-28) =================
|
||||
# SII tier, steel-bar path (Magic 43-54, Smithing 30, session target 55).
|
||||
# Constants: break.every [400, 700] casts (the example pins the midpoint
|
||||
# 550), break.for [45, 120] s; steel capacity = floor(27 / (1 iron + 2 coal))
|
||||
# = 9 casts per bank cycle — restocks every 9 casts; the counter sequences
|
||||
# are MONOTONIC and INDEPENDENT (restocking never resets the break counter).
|
||||
#
|
||||
# Step 0 — prep (one-time startup ~300-600 s): account has 30 Smithing +
|
||||
# 43-54 Magic and the LA/HLA-tier capital (>= ~1.31M gp). At the GE bank:
|
||||
# choose the session target (55); open GE (a2); place offers — staff (a3),
|
||||
# 1,000 nature runes + LA candidate OR - for the SII window - the selected
|
||||
# recipe's first pack (steel: 9 iron ore + 18 coal + 9 natures, a4); wait
|
||||
# for fills (ge_offers_done) and collect everything (a5); equip the staff
|
||||
# (a6); loadout = 9 iron + 18 coal + 9 natures (a7). Cast counter := 0.
|
||||
# Steel is the highest UNLOCKED recipe (Smithing 30); bronze (1), iron (15)
|
||||
# and silver (20) are unlocked but LOWER, so steel is selected. Smithing 20
|
||||
# accounts select silver-bar (capacity 27) and steel stays locked (never an
|
||||
# unmet gate).
|
||||
# Step 1 — casts #1..#9: each cast consumes 1 iron ore + 2 coal + 1 nature
|
||||
# and produces 1 steel bar (+53 Magic xp, +17.5 Smithing xp). After cast #9
|
||||
# the inventory holds 9 bars (capacity reached) -> FIRST RESTOCK at cast 9:
|
||||
# deposit the 9 bars (a10); the bank holds 0 steel inputs (all sales were
|
||||
# GE buys), so the fast path yields nothing -> open GE (a2), RE-BUY the
|
||||
# pack deficit 9 iron + 18 coal + 9 natures (a11, live low + 5 %), collect
|
||||
# (a12) -> inventory rebuilt. Restocks repeat every 9 casts (9, 18, 27, ...,
|
||||
# and at 558 after the first break below) — capacity-derived, deterministic.
|
||||
# Step 2 — FIRST SCHEDULED BREAK at cast 550 (midpoint of break.every
|
||||
# [400, 700]): the 61st cycle is mid-flight — take-break 45-120 s (a13),
|
||||
# resume at cast 551, finish the cycle (restock at 558). The break fired on
|
||||
# the CAST COUNTER while a bank cycle was still running: breaks and banking
|
||||
# are independent by construction, and restocking did NOT shift the break.
|
||||
# Step 3 — break #2 at cast 1,100 (exactly 550 after #1 — monotonic,
|
||||
# unaffected by the 9-cast restock cadence); break #3 at 1,650; restocks
|
||||
# continue at 1,107, 1,116, ... (every 9). On the alch tiers (LA and the
|
||||
# post-55 HLA tier) the restock cadence is the 901-cast batch: restock #1
|
||||
# at cast 901, restock #2 at cast 1,802 — monotonic, independent pins just
|
||||
# like the breaks (restocking never resets or shifts the break counter).
|
||||
# The SII window ends at Magic 55:
|
||||
# with the default target 55 the session completes at the LA/SII -> HLA
|
||||
# handoff; with a target above 55 the HLA tier (a8, 65 xp/cast, 901-cast
|
||||
# batch model) executes until the target.
|
||||
# Fallback chain pinned: steel inputs unfillable at the GE (3 failed offers)
|
||||
# -> drop to silver-bar (20, next lower unlocked) -> if silver is also
|
||||
# unfillable or margin-negative at allowed fills -> skip SII this window and
|
||||
# stay on LA throughout 43-54 (a8 handles the SII-skip window explicitly).
|
||||
# =====================================================================================================
|
||||
|
||||
risk:
|
||||
ban_level: low
|
||||
notes:
|
||||
- "3-tick cast cadence is the main detection vector; keep anti_ban delays (cadence pin: additive post-cast sleep [1.6, 3.4]s; session-realized ~742 casts/hr on the alch tiers and ~234 casts/hr on the steel SII anchor, incl. startup + restock + breaks over a 2 h session — loop-only 837 is a ceiling reference, never the output)."
|
||||
- "Breaks are CAST-COUNT-based (every [400, 700] completed casts, 45-120s AFK) and independent of bank visits — never treat a restock trip as a break, and never reset the break counter on restock (break interval 550 and restock cadences 901/9 are coprime by construction)."
|
||||
- "The valuable-item warning fires on item GE value (not alch value) — the script must handle the warning widget when alching high-value items (HLA page)."
|
||||
- "SII: withdraw the EXACT recipe inputs (unnoted, per the recipes table) sized to the derived capacity (floor(27 / input qty)) and cast on the declared target_input (primary ore) — never on coal, never on a noted stack; bank the produced bars when bars_in_inventory >= capacity."
|
||||
- "SII ore-buy bursts are pace-sensitive like any GE buy; respect the 4h limit window; re-check the allowed-fill complete-cost margin per window because ore/bar prices move independently."
|
||||
|
||||
# --- recovery block (owner guidance 2026-08-28: every activity must cover its complete runnable lifecycle) ---
|
||||
# - Missing materials / depleted supplies: LA/HLA restock at candidate OR nature
|
||||
# < 100 (carried_batch 1,000/1,000); SII restocks at bars >= the selected
|
||||
# recipe's capacity (floor(27 / input qty)) or any selected-recipe input < 1 —
|
||||
# deterministic threshold transitions to bank_supplies; the restock phase
|
||||
# (a10 -> a2 -> a11 -> a12) RE-BUYS the deficit at the GE — never withdraw a
|
||||
# batch that was never purchased.
|
||||
# - GE offers: partial fills are collected (a5/a12) and the remainder re-placed
|
||||
# at the current edge (a3/a4/a11); after 3 consecutive no-fill rounds (initial
|
||||
# or restock) the SII recipe falls back to the next lower unlocked recipe;
|
||||
# with no fallback recipe left, SII is skipped and LA takes over; with no
|
||||
# fallback candidate, the run stops (failed). Unfilled offers at session end
|
||||
# are left resting by design (float reserve; coins return when they fill or
|
||||
# the operator aborts them — the single operator-touch point).
|
||||
# - Staff of fire cannot be equipped (a6): bounded retries (3), then FAIL
|
||||
# CLOSED — log ERROR + alert + stop. No fire-rune fallback is modeled (it
|
||||
# would need its own purchase/supply/rate path; the owner decision rejects a
|
||||
# prose-only fallback).
|
||||
# - Invalid loadout (wrong item in hand / spell unavailable): re-run
|
||||
# build-loadout (a7); 3 consecutive failed casts -> failed (stop, log ERROR
|
||||
# sentinel, alert).
|
||||
# - Capital: both capital stops are assets-based (total assets = cash +
|
||||
# supplies at current buy cost) — cash converted into supplies is not a loss
|
||||
# and never fires a stop by itself (see stop_conditions).
|
||||
# - Explicit completion/stop: stop_conditions above (session target 55 or the
|
||||
# >55 HLA tier, 2 h session horizon, assets floor 312,650 / 10,150, loss
|
||||
# reserve 690,075, repeated failures, fail-closed staff equip).
|
||||
|
||||
sources:
|
||||
- "OSRS wiki — Low Level Alchemy (21 Magic, 31 xp/cast, members=No, 3-tick, 40% of item value; 'recommended to use High Level Alchemy instead' at 55 Magic)"
|
||||
- "OSRS wiki — Superheat Item (43 Magic, 53 xp/cast, members=No; smelts ore into bars without a furnace; cannot be cast on noted ore; grants the bar's Smithing XP; requires the bar's Smithing level and materials)"
|
||||
- "OSRS wiki — High Level Alchemy (55 Magic, 65 xp/cast, members=No, 60% of item value; GE buying for break-even/profit; noted-item casting; valuable-item warning)"
|
||||
- "OSRS wiki — Smithing (bar smelting table: smithing levels, per-bar XP and ore/coal quantities for bronze/iron/silver/steel/gold/mithril/adamantite/runite)"
|
||||
- "OSRS wiki — Grand Exchange (offers persist until filled or aborted; filled items and coin refunds are collected from the booth/collection box; partial fills are separately collectable) — verified 2026-08-28"
|
||||
- "OSRS wiki — Grand Exchange/Buying limits (4-hour window; the limit resets 4 hours after the FIRST unit is bought; outstanding offers remain active and a limit reset is NOT an offer expiry) — verified 2026-08-28"
|
||||
- "prices.runescape.wiki/api/v1/osrs/mapping (id 561 nature rune: members=false, limit 18000, value 180, lowalch 72; limit cross-checked against Module:Exchange/Nature_rune — agree)"
|
||||
- "prices.runescape.wiki/api/v1/osrs/latest (nature rune buy 145, snapshot 2026-08-27; steel-bar fixture prices: iron ore 100, coal 150, steel bar 600)"
|
||||
- "OSRS wiki — Staff of fire (page verified 2026-08-28 for the equip requirement: id 1387, F2P item, tradeable, options Wield — NO requirements row in the Infobox Item and NO requirement statement in the prose; contrast Battlestaff, whose prose states 'requires 30 Attack and 30 Magic to wield')"
|
||||
- "docs/schema.md run_control (iteration unit; break.every counts iterations) + docs/action-grammar.md:135 (anti_ban.delay = additive post-action sleep) + verbs ge_open/ge_buy/ge_collect/ge_offers_done (separate GE primitives) — the cadence + break + GE + lifecycle model; owner guidance 2026-08-28 (capacity-derived SII, rate_model, configurable target, fail-closed staff); governor comment 10394 (verified build-loadout a7, sign-corrected loss stop)"
|
||||
verified: "2026-08-27" # keep quoted (YAML 1.1 date parsing); prices last re-fetched live 2026-08-27
|
||||
|
||||
related:
|
||||
- low-alch-f2p
|
||||
- f2p-alch-catalog
|
||||
- high-alch-p2p
|
||||
@ -39,8 +39,10 @@
|
||||
"item": { "type": "string" },
|
||||
"item_id": { "type": "integer" },
|
||||
"cost_per_cycle": { "type": "number" },
|
||||
"cost_per_cycle_max_fill": { "type": "number" },
|
||||
"income_per_cycle": { "type": "number" },
|
||||
"net_per_cycle": { "type": "number" },
|
||||
"net_per_cycle_max_fill": { "type": "number" },
|
||||
"gp_per_hour_low": { "type": "number" },
|
||||
"gp_per_hour_high": { "type": "number" },
|
||||
"ceiling_gp_per_hour": { "type": "number", "exclusiveMinimum": 0 },
|
||||
@ -63,6 +65,105 @@
|
||||
}
|
||||
},
|
||||
|
||||
"selection": {
|
||||
"type": "object",
|
||||
"required": ["mode", "eligible_rule", "fallback"],
|
||||
"additionalProperties": false,
|
||||
"properties": {
|
||||
"mode": { "enum": ["highest-unlocked"] },
|
||||
"eligible_rule": { "type": "string", "minLength": 10 },
|
||||
"fallback": { "type": "string", "minLength": 10 }
|
||||
}
|
||||
},
|
||||
|
||||
"recipes": {
|
||||
"type": "object",
|
||||
"minProperties": 1,
|
||||
"propertyNames": { "pattern": "^[a-z0-9]+(-[a-z0-9]+)*$" },
|
||||
"additionalProperties": {
|
||||
"type": "object",
|
||||
"required": ["bar", "smithing_level", "target_input", "inputs"],
|
||||
"additionalProperties": false,
|
||||
"properties": {
|
||||
"bar": { "type": "string", "minLength": 2 },
|
||||
"bar_item_id": { "type": "integer", "minimum": 1 },
|
||||
"smithing_level": { "type": "integer", "minimum": 1, "maximum": 126 },
|
||||
"smithing_xp": { "type": "number", "exclusiveMinimum": 0 },
|
||||
"target_input": { "type": "string", "minLength": 2 },
|
||||
"inputs": {
|
||||
"type": "array",
|
||||
"minItems": 1,
|
||||
"items": {
|
||||
"type": "object",
|
||||
"required": ["item", "qty", "source"],
|
||||
"additionalProperties": false,
|
||||
"properties": {
|
||||
"item": { "type": "string", "minLength": 2 },
|
||||
"item_id": { "type": "integer", "minimum": 1 },
|
||||
"qty": { "type": "integer", "minimum": 1 },
|
||||
"source": { "enum": ["ge", "p2p", "drops", "craft", "bank", "npc-shop"] }
|
||||
}
|
||||
}
|
||||
},
|
||||
"rates": {
|
||||
"type": "object",
|
||||
"required": ["capacity", "casts_per_hour", "magic_xp_per_hour"],
|
||||
"additionalProperties": false,
|
||||
"properties": {
|
||||
"capacity": { "type": "integer", "minimum": 1 },
|
||||
"casts_per_hour": {
|
||||
"type": "object",
|
||||
"required": ["min", "mid", "max"],
|
||||
"additionalProperties": false,
|
||||
"properties": {
|
||||
"min": { "type": "number", "minimum": 0 },
|
||||
"mid": { "type": "number", "minimum": 0 },
|
||||
"max": { "type": "number", "minimum": 0 }
|
||||
}
|
||||
},
|
||||
"magic_xp_per_hour": {
|
||||
"type": "object",
|
||||
"required": ["min", "mid", "max"],
|
||||
"additionalProperties": false,
|
||||
"properties": {
|
||||
"min": { "type": "number", "minimum": 0 },
|
||||
"mid": { "type": "number", "minimum": 0 },
|
||||
"max": { "type": "number", "minimum": 0 }
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
"rate_model": {
|
||||
"type": "object",
|
||||
"required": ["anchor_tier", "cast_ticks", "restock_trip_s", "session_horizon_s"],
|
||||
"additionalProperties": false,
|
||||
"properties": {
|
||||
"anchor_tier": { "enum": ["la", "sii", "hla"] },
|
||||
"anchor_recipe": { "type": "string" },
|
||||
"cast_ticks": { "type": "integer", "minimum": 1 },
|
||||
"restock_trip_s": {
|
||||
"type": "array",
|
||||
"items": { "type": "number", "minimum": 0 },
|
||||
"minItems": 2,
|
||||
"maxItems": 2
|
||||
},
|
||||
"session_horizon_s": { "type": "integer", "minimum": 1 },
|
||||
"startup_s": {
|
||||
"type": "array",
|
||||
"items": { "type": "number", "minimum": 0 },
|
||||
"minItems": 2,
|
||||
"maxItems": 2
|
||||
},
|
||||
"alch_carry_batch": { "type": "integer", "minimum": 1 },
|
||||
"alch_restock_threshold": { "type": "integer", "minimum": 0 },
|
||||
"sii_capacity_slots": { "type": "integer", "minimum": 1 }
|
||||
}
|
||||
},
|
||||
|
||||
"pickaxe_tiers": {
|
||||
"type": "object",
|
||||
"minProperties": 1,
|
||||
|
||||
1412
tools/validate.py
1412
tools/validate.py
File diff suppressed because it is too large
Load Diff
Loading…
Reference in New Issue
Block a user