codex: low-alch-members — complete GE lifecycle, capital model, monotonic counters, fail-closed staff (bounce-fix attempt 4)
Owner guidance 10325 (governor 10297 findings, exactly): - GE acquisition path for initial buy AND every restock: open -> place -> wait/fill -> collect (ge_open/ge_buy/ge_collect; new wait_offers state), partial-fill collect + re-place recovery, bank-stock fast path only when the bank actually holds stock — never withdraw an unbought batch. - Capital model: staff cap 5,000 + first batch at max fill 570,150 + 6-batch worst-case loss reserve 162,990 + float 570,150 (~1.31M); capital stops use TOTAL ASSETS (cash + supplies), never raw cash. - Monotonic counters: breaks at 550/1,100/1,650 independent of restocks at 901/1,802 (gcd 550,901=1); validator regression rejects the old 1,452 restart bug and enforces the pins. - Rates: loop-only 837.2 labelled ceiling; steady-state 639-1020 (mid 791.2); session-realized 586-977 (mid 741.8) over the explicit 2h session horizon -> xp 23,000, gp -2,930..-1,760. - Staff equip FAIL-CLOSED after bounded retries; fire-rune fallback prose removed everywhere. Preserves one-cast iteration, cast-count breaks, rune javelin tips anchor, pacing/equipment fixes. version 4 -> 5.
This commit is contained in:
parent
5ddfc6cdbc
commit
a197b34aa8
@ -3,7 +3,7 @@ title: Low-Level Alchemy (Members)
|
||||
domain: economy
|
||||
tags: [alching, magic-training, members, loss-training]
|
||||
status: verified
|
||||
version: 4 # 4: bounce-fix 3 2026-08-28 (owner guidance) — iteration = one cast, break.every in CAST counts (independent of bank visits), numeric carried_batch/restock_threshold, realized rates incl. setup+restock+breaks, full-lifecycle actions, pinned worked example
|
||||
version: 5 # 5: bounce-fix 4 2026-08-28 (owner guidance 10325) — complete GE acquisition path (open -> place -> fill -> collect) for initial buy AND every restock (bank-stock fast path only when the bank holds stock); fail-closed staff equip (bounded retries, no fire-rune fallback); capital model (cash vs supplies, staff cost, max-fill worst case, 6-batch loss reserve, float); monotonic break/restock counters (breaks 550/1,100/1,650 independent of restocks 901/1,802) + validator regression; startup-vs-steady-state rates over a 2 h session horizon
|
||||
updated: "2026-08-28" # ISO dates must stay quoted — YAML 1.1 parses bare dates to datetime.date
|
||||
|
||||
summary: >
|
||||
@ -13,28 +13,35 @@ summary: >
|
||||
(mapping lowalch != null, members=true, live GE prices 2026-08-27). At
|
||||
current prices the method burns a small amount of GP per cast for 31 XP —
|
||||
run it for XP, not GP. Least-loss liquid anchor at last check: rune
|
||||
javelin tips (-3/cast). Model pin (owner guidance 2026-08-28): one
|
||||
javelin tips (-3/cast). Model pins (owner guidance 2026-08-28): one
|
||||
iteration = one cast; breaks every 400-700 COMPLETED CASTS (cast-count
|
||||
based, independent of bank visits); restock when candidate or nature
|
||||
drops below the numeric restock_threshold (100) against a carried_batch
|
||||
of 1,000/1,000 — pinned worked example below. Handoff: switch to High
|
||||
Level Alchemy at level 55 (hard level gate + strictly more coins AND XP
|
||||
per cast; see sources).
|
||||
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; rates are
|
||||
session-realized (startup + restock + breaks included, see economy).
|
||||
Handoff: switch to High Level Alchemy at level 55 (hard level gate +
|
||||
strictly more coins AND XP per cast; see sources).
|
||||
|
||||
accounts:
|
||||
membership: members
|
||||
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; NO level requirement documented on the OSRS wiki — verified 2026-08-28, see sources — this is the default path)"
|
||||
- "A bank with GE access within reach (alch spot = GE bank booth; restock trip 60-120s)"
|
||||
- "Working capital >= 543,000 gp for one carried_batch (1,000 x 403 gp javelin tips + 1,000 x 140 gp natures, live 2026-08-27)"
|
||||
- "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 — this is the default path). Equip failure is FAIL-CLOSED: flow performs bounded retries (3), then logs ERROR + alerts + stops — there is no fire-rune fallback in this model"
|
||||
- "A bank with GE access within reach (alch spot = GE bank booth; restock trip [60, 120] s)"
|
||||
- "Starting capital >= ~1.31M gp CASH (model breakdown: staff buy hard cap 5,000 + first batch at MAX allowed fill 570,150 + session loss reserve 162,990 = 6 worst-case batches at live-low+5% fills (covers Magic 21 -> 55) + resting-offer float 570,150). The capital stop check uses TOTAL ASSETS (cash + supplies at current buy cost), never raw cash — cash legitimately converts into supplies mid-run"
|
||||
- "30 Attack + 50 Magic ONLY if adopting the optional Bryophyta's staff + Tome of Fire technique — below that the Staff of Fire path applies"
|
||||
|
||||
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); equip requirement: none documented on the OSRS wiki (verified 2026-08-28)"
|
||||
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, F2P item, tradeable, no requirements row in the infobox and none in the prose — compare Battlestaff which states 'requires 30 Attack and 30 Magic'); Low Level Alchemy (Cost)"
|
||||
techniques:
|
||||
- name: cast on noted (stacked) items
|
||||
@ -52,30 +59,42 @@ economy:
|
||||
# OSRS wiki (spell infoboxes, Module:Exchange limits, item pages).
|
||||
# Re-verified at bounce fix 2026-08-27 with a fresh live fetch; the
|
||||
# modeled anchor is the ACTUAL least-loss liquid candidate.
|
||||
# Bounce-fix 3 (2026-08-28, owner guidance): all rate fields are REALIZED
|
||||
# figures — setup/restock/breaks included, not just the cast loop.
|
||||
# Bounce-fix 4 (2026-08-28, owner guidance 10325): all rate fields are
|
||||
# SESSION-REALIZED figures — startup + restock + mandatory breaks
|
||||
# included; loop-only and steady-state figures retained as labelled
|
||||
# references; the 2 h session horizon is explicit (stop_conditions).
|
||||
item: Rune javelin tips # least-loss liquid anchor 2026-08-27 (see profit_drivers)
|
||||
item_id: 19580
|
||||
cost_per_cycle: 543 # javelin tips buy 403 + nature rune 140 (staff of fire)
|
||||
cost_per_cycle: 543 # javelin tips buy 403 + nature rune 140 (staff of fire, live low 2026-08-27)
|
||||
income_per_cycle: 540 # lowalch of rune javelin tips (40% of value 1350)
|
||||
net_per_cycle: -3
|
||||
gp_per_hour_low: -2960 # realized (incl. restock+breaks), fastest cycle 3.4s -> 986.4 casts/hr x -3 = -2,959
|
||||
gp_per_hour_high: -1980 # realized (incl. restock+breaks), slowest cycle 5.2s -> 660.6 casts/hr x -3 = -1,982
|
||||
xp_per_hour: 24500 # realized midpoint 791.3 casts/hr x 31 xp = 24,530 (pin 24,500)
|
||||
# ---- realized-rate derivation (pinned; owner guidance 2026-08-28) ----
|
||||
# LOOP: cycle = 1.8s cast (3 ticks x 0.6s) + anti_ban.delay [1.6, 3.4]s ADDITIVE
|
||||
# (docs/action-grammar.md:135) = 3.4-5.2s, midpoint 4.3s -> loop-only
|
||||
# casts/hr = 3600/4.3 = 837.2; loop-only xp = 25,953 (837.2 x 31);
|
||||
# loop-only gp midpoint = -2,512 (837.2 x -3).
|
||||
# OVERHEAD per 901-cast batch (carried_batch 1000 - restock_threshold 100):
|
||||
# restock trip [60, 120]s (midpoint 90s, GE-adjacent booth);
|
||||
# breaks: every [400, 700] casts (midpoint 550) for [45, 120]s (midpoint
|
||||
# 82.5s) -> 901/550 = 1.64 breaks x 82.5s = 135s.
|
||||
# Total overhead = 90 + 135 = 225s per 901 casts.
|
||||
# REALIZED casts/hr = 901 / ((901 x cycle_s + 225) / 3600):
|
||||
# fast 3.4s -> 986.4; midpoint 4.3s -> 791.3; slow 5.2s -> 660.6.
|
||||
# xp_per_hour = 791.3 x 31 = 24,530 (pin 24,500; range 20,480..30,580).
|
||||
# gp_per_hour = realized casts/hr x -3: fast -2,959 (low), slow -1,982 (high), midpoint -2,374.
|
||||
gp_per_hour_low: -2930 # session-realized fast bound: 977.2 casts/hr x -3 = -2,932 (3.4 s cycle, 300 s startup, 2 h horizon)
|
||||
gp_per_hour_high: -1760 # session-realized slow bound: 585.9 casts/hr x -3 = -1,758 (5.2 s cycle, 600 s startup, 2 h horizon)
|
||||
xp_per_hour: 23000 # session-realized midpoint: 741.8 casts/hr x 31 = 22,995 (pin 23,000)
|
||||
# ---- rate model (pinned; owner guidance 2026-08-28) ----
|
||||
# LOOP (idealised, zero overhead — ceiling reference ONLY, never the
|
||||
# entry's output): cycle = 1.8 s cast (3 ticks x 0.6 s) +
|
||||
# anti_ban.delay [1.6, 3.4] s ADDITIVE (docs/action-grammar.md:135)
|
||||
# = 3.4-5.2 s, midpoint 4.3 s -> loop-only casts/hr = 3600/4.3 = 837.2
|
||||
# (range 692.3..1,058.8); loop-only xp mid = 25,953; gp mid = -2,512.
|
||||
# STEADY-STATE (mandatory breaks + restock trips, no startup): per
|
||||
# 901-cast batch: 901 x cycle + restock trip [60, 120] s (mid 90) +
|
||||
# break share (break.for mid 82.5 s per break.every mid 550 casts:
|
||||
# 45 s/700 at the fast end, 120 s/400 at the slow end):
|
||||
# fast 3.4 s: 901 x 3.4 + 60 + 45 x 901/700 = 3,181.3 s -> 1,019.7 casts/hr
|
||||
# mid 4.3 s: 901 x 4.3 + 90 + 82.5 x 901/550 = 4,099.5 s -> 791.3 casts/hr
|
||||
# slow 5.2 s: 901 x 5.2 + 120 + 120 x 901/400 = 5,075.5 s -> 639.2 casts/hr
|
||||
# SESSION-REALIZED (2 h horizon = 7,200 s; one-time startup 300-600 s,
|
||||
# mid 450 s -> 450/7200 = 6.25 %): realized = steady-state x (1 -
|
||||
# startup/session): fast 977.2, mid 741.8, slow 585.9 casts/hr.
|
||||
# xp mid = 741.8 x 31 = 22,995 -> pin 23,000; gp = casts/hr x -3:
|
||||
# low -2,932 (fast), high -1,758 (slow), mid -2,225.
|
||||
# BATCH ECONOMICS (901 casts; deposits 901 x 540 = 486,540 gp per batch):
|
||||
# input cost at live low: 901 x 543 = 489,243 -> net -2,703/batch
|
||||
# input cost at MAX fill (live low + 5 %): 901 x 570.15 = 513,705 -> net
|
||||
# -27,165/batch (worst case). Reserve = 6 worst-case batches (Magic
|
||||
# 21 -> 55 = ~5,300 casts = ~6 batches) = 162,990 gp; the capital stop
|
||||
# checks TOTAL ASSETS, not raw cash (see accounts + stop_conditions).
|
||||
supplies:
|
||||
- item: rune javelin tips
|
||||
qty_per_cycle: 1
|
||||
@ -101,37 +120,58 @@ economy:
|
||||
- "9. Adamant spear(p) (id 1259, lowalch 832, buy 450, margin +382, GE limit 125)"
|
||||
- "10. Mystic mist staff (id 20733, lowalch 17000, buy 75727, margin -58727, GE limit 8) — buy spiked ABOVE alch value 2026-08-27; a true loss trap, do not buy"
|
||||
- "Caveat: thin items (limits 5-125) cannot sustain a run and their 'low' fills can be stale — a bot cannot reliably buy at those prices. The dependable loss-minimizers are the liquid high-limit pair modeled above: rune javelin tips (-3/cast) and rune arrow (-25/cast)."
|
||||
- "Batch-scale economics (default staff-of-fire path, worst case 1 nature/cast): carried_batch 1,000/1,000, restock every 901 casts — one batch = -2,703 gp, +27,931 xp, 2 x 540 gp coin deposits."
|
||||
- "Batch-scale economics (default staff-of-fire path, worst case 1 nature/cast): carried_batch 1,000/1,000, restock every 901 casts — one batch = -2,703 gp at live-low fills (-27,165 at MAX allowed fills), +27,931 xp, deposits 486,540 gp; unfilled-offer float (up to 570,150 gp) is separate from loss (see accounts)."
|
||||
|
||||
state_machine:
|
||||
initial: idle
|
||||
terminal: [complete, failed]
|
||||
states:
|
||||
idle:
|
||||
goal: "acquire + equip the staff of fire, GE-buy candidate + natures, build the starting inventory to carried_batch (1,000 candidate + 1,000 nature)"
|
||||
next: [casting, complete, failed]
|
||||
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 (a3/a4/a5); 3 consecutive no-fill rounds (offer cannot fill at the accepted edge) -> failed. An offer that is still unfilled at session end is left resting by design — its coins are tied up (float reserve) and return when it fills or is aborted by the operator (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 loadout to carried_batch 1,000 candidate + 1,000 nature (a8; purchases from a6 are already in the inventory; a8 deposits overflow and confirms the counts)"
|
||||
next: [casting, failed]
|
||||
casting:
|
||||
goal: "cast Low Level Alchemy on the current candidate item — each cast consumes 1 candidate + 1 nature and pays 540 gp (lowalch), +31 xp, net -3 gp; take a break when the completed-cast counter hits run_control.break.every ([400, 700] casts)"
|
||||
goal: "cast Low Level Alchemy on the candidate (a9) — each cast consumes 1 candidate + 1 nature and pays 540 gp (lowalch), +31 xp, net -3 gp; 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: "deposit coins + products, withdraw candidate + natures back to carried_batch (1,000/1,000), resume casting"
|
||||
next: [casting, failed]
|
||||
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 (default 55 -> hand off to HLA)"
|
||||
goal: "reached the run's XP/level target (default 55 -> hand off to HLA) or the 2 h session horizon"
|
||||
failed:
|
||||
goal: "hard failure — stop, log ERROR sentinel, alert"
|
||||
transitions:
|
||||
- from: idle
|
||||
when: "staff equipped AND candidate == carried_batch AND nature == carried_batch (1,000 and 1,000)"
|
||||
to: casting
|
||||
when: "staff + candidate + nature offers all placed (a3/a4/a5)"
|
||||
to: wait_offers
|
||||
- from: idle
|
||||
when: "magic level >= target (55, hand off to HLA)"
|
||||
when: "magic level >= target (55) at session start"
|
||||
to: complete
|
||||
- from: idle
|
||||
when: "3 consecutive purchase/equip failures with no fallback available (recovery block below)"
|
||||
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 (a3/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 loadout at carried_batch 1,000/1,000 (a8)"
|
||||
to: casting
|
||||
- from: ready
|
||||
when: "staff equip failed after bounded retries — FAIL CLOSED"
|
||||
to: failed
|
||||
- from: casting
|
||||
when: "candidate count < restock_threshold (100) OR nature rune count < restock_threshold (100) — deterministic restock trigger, pinned numbers"
|
||||
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, hand off to HLA)"
|
||||
@ -140,8 +180,14 @@ state_machine:
|
||||
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)"
|
||||
when: "restock complete: candidate == carried_batch (1,000) AND nature == carried_batch (1,000) — 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
|
||||
|
||||
# --- handoff note (wiki-verified 2026-08-27, do not copy from other entries) ---
|
||||
# Low Level Alchemy: level 21, 31 xp/cast, 1 nature + 3 fire (spellbook: Normal).
|
||||
@ -171,27 +217,27 @@ actions:
|
||||
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/a5/a11) or collects (a6/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)"
|
||||
on_fail: retry # retry once; on a second failure use the fire-rune fallback (see a3 note / recovery block)
|
||||
anti_ban:
|
||||
delay: [1200, 3000]
|
||||
|
||||
- id: a3
|
||||
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 which states 'requires 30 Attack and 30 Magic'; verified 2026-08-28). FAILURE PATH — if Wield is unavailable or the staff cannot be equipped, fall back to buying 3 fire runes per cast (3 fire + 1 nature = 155 gp rune cost vs 140, net -18/cast at the anchor), log WARN and continue; never loop on equip attempts."
|
||||
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: [600, 1800]
|
||||
delay: [1200, 3000]
|
||||
|
||||
- id: a4
|
||||
step: buy-supplies
|
||||
@ -200,8 +246,9 @@ actions:
|
||||
params:
|
||||
item: "current least-loss live candidate (default: rune javelin tips)"
|
||||
qty: "carried_batch = 1,000 (fits the 4h GE limit window of 10,000)"
|
||||
max_price: "live low + 5%"
|
||||
on_fail: retry # re-place at live low +5% with paced offers; 3 consecutive failures -> failed (recovery block)
|
||||
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]
|
||||
|
||||
@ -212,21 +259,45 @@ actions:
|
||||
params:
|
||||
item: "nature rune"
|
||||
qty: "carried_batch = 1,000 (4h GE limit 18,000)"
|
||||
max_price: "live low + 5%"
|
||||
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 which states '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: "candidate 1,000 + nature runes 1,000 (= carried_batch; both stackable, two inventory slots)"
|
||||
withdraw: "to carried_batch: candidate 1,000 + nature runes 1,000 (only the shortfall — collected purchases from a6 are already in the inventory; both stackable, two inventory slots)"
|
||||
on_fail: retry
|
||||
anti_ban:
|
||||
delay: [500, 1100]
|
||||
|
||||
- id: a7
|
||||
- id: a9
|
||||
step: cast-alch
|
||||
verb: use_item_on
|
||||
target: "candidate item in inventory"
|
||||
@ -237,24 +308,49 @@ actions:
|
||||
consumption: "1 candidate + 1 nature per cast (staff of fire default); pays 540 gp (lowalch) + 31 xp, net -3 gp"
|
||||
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 = 1.8s + 1.6-3.4s = 3.4-5.2s, midpoint 4.3s -> realized ~791 casts/hr incl. restock+breaks (pinned in economy)
|
||||
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 (pinned in economy)
|
||||
|
||||
- id: a8
|
||||
step: restock
|
||||
- id: a10
|
||||
step: restock-deposit
|
||||
verb: bank_inventory
|
||||
target: bank
|
||||
params:
|
||||
deposit: [all coins, all products]
|
||||
withdraw: "candidate + nature runes up to carried_batch (1,000/1,000)"
|
||||
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: a9
|
||||
- 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"
|
||||
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:
|
||||
@ -265,63 +361,85 @@ run_control:
|
||||
for: [45, 120] # seconds of idle AFK per break
|
||||
stop_conditions:
|
||||
- "magic level >= target (55 -> hand off to HLA)"
|
||||
- "gp under floor (working capital below one carried_batch = 543,000 gp)"
|
||||
- "session elapsed >= 2 h (session horizon — startup is amortised over this window in the rate model)"
|
||||
- "total assets (cash + supplies at current buy cost) < 575,150 — cannot fund the next batch at max fill (570,150) plus staff replacement (5,000); assets, NOT raw cash: cash that became supplies is not a loss"
|
||||
- "session net loss (total assets - initial capital) > 162,990 — the 6-batch worst-case loss reserve is exhausted"
|
||||
- "3 consecutive failed casts (client issue — do not loop)"
|
||||
- "3 consecutive failed GE purchases with no fallback candidate available"
|
||||
- "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 (midpoint 550); break.for = [45, 120] s;
|
||||
# default staff-of-fire path consumes 1 candidate + 1 nature per cast (worst case 1:1 —
|
||||
# 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 —
|
||||
# with Bryophyta's staff the nature side drains slower, so the candidate stays binding).
|
||||
# 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 (validator regression: the old buggy
|
||||
# 'restart the interval at the restock' example is rejected by the gate).
|
||||
#
|
||||
# Step 0 — before the first inventory: account holds >= 543,000 gp working capital
|
||||
# (1,000 x 403 + 1,000 x 140). At the GE bank: GE-buy staff of fire, Wield it
|
||||
# (no documented requirement), GE-buy 1,000 rune javelin tips + 1,000 nature runes,
|
||||
# withdraw both -> loadout = carried_batch 1,000/1,000. Cast counter := 0.
|
||||
# Step 1 — casts #1..#550: each cast consumes 1 candidate + 1 nature (-543 gp) and pays
|
||||
# 540 gp (lowalch) + 31 xp -> net -3 gp. Cast counter 0 -> 550 (~39 min at midpoint).
|
||||
# Step 2 — FIRST SCHEDULED BREAK at cast 550 (midpoint of break.every [400, 700]): run
|
||||
# take-break for 45-120 s. Resume casting at cast 551. The break fired on the CAST
|
||||
# COUNT, not on any bank visit; the restock counter is untouched.
|
||||
# Step 3 — casts #551..#901: countdown candidate 1000-901 = 99 < 100 (restock_threshold)
|
||||
# and nature 1000-901 = 99 < 100 simultaneously (worst case 1:1) -> the transition
|
||||
# fires at the end of cast #901: FIRST RESTOCK/BANK EVENT at cast 901.
|
||||
# Coins deposited at this restock: 901 x 540 = 486,540 gp; batch net so far -2,703 gp;
|
||||
# batch xp so far 901 x 31 = 27,931.
|
||||
# Step 4 — restock: deposit coins + products, withdraw 901 candidate + 901 nature ->
|
||||
# carried_batch restored to 1,000/1,000. Resume casting at cast 902 (cast counter
|
||||
# continues; the break counter also continues — restocking never resets either).
|
||||
# Step 5 — SECOND BREAK when the cast-count interval since break #1 completes
|
||||
# ([400, 700], midpoint: cast 902 + 550 = 1,452): take-break, resume at 1,453.
|
||||
# Step 6 — restock #2 fires at cast 1,802 (901-cast batch cadence), and so on, until a
|
||||
# stop_condition fires (Magic >= 55 -> HLA handoff; gp under floor; 3 failed casts).
|
||||
# Bank visits and breaks are INDEPENDENT by construction: restock cadence = 901 casts;
|
||||
# break cadence = 400-700 casts, and the two counters do not interact.
|
||||
# Step 0 — preparation (one-time startup, ~300-600 s): account holds >= ~1.31M gp
|
||||
# cash (staff cap 5,000 + first batch max 570,150 + reserve 162,990 + float
|
||||
# 570,150). At the GE bank: open GE (a2); place offers — staff (a3), 1,000
|
||||
# rune javelin tips (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 (-543 gp)
|
||||
# and pays 540 gp (lowalch) + 31 xp -> net -3 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 540 = 486,540 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: -2,703 gp (live-low fills) or
|
||||
# -27,165 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 (HLA handoff),
|
||||
# the 2 h session horizon, the capital stops (assets floor 575,150 or net
|
||||
# loss > 162,990), 3 failed casts, or 3 consecutive no-fill GE rounds.
|
||||
# ============================================================================================
|
||||
|
||||
risk:
|
||||
ban_level: low
|
||||
notes:
|
||||
- "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; realized ~791 casts/hr at the 4.3s midpoint cycle incl. restock + breaks; loop-only 837)."
|
||||
- "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."
|
||||
- "GE buy bursts: pace offers, respect the 4h limit window (10,000 javelin tips / 18,000 natures); thin items (limit < 100) cannot sustain a long run."
|
||||
- "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-120 s AFK) and independent of bank visits — never treat a restock trip as a break, and never reset the break counter on restock (break/restock gcd(550, 901) = 1)."
|
||||
- "GE buy bursts: pace offers, respect the 4h limit window (10,000 javelin tips / 18,000 natures); thin items (limit < 100) cannot sustain a long run; offers persist until filled or aborted and a 4h limit reset is NOT an offer expiry."
|
||||
- "Thin-item 'latest low' fills can be stale — confirm fill price with a live GE offer before committing a run; the liquid high-limit pair (rune javelin tips / rune arrow) is the dependable loss-minimizer."
|
||||
|
||||
# --- 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; restock
|
||||
# action a8 rebuilds to carried_batch and the loop resumes (worked example steps 3-4).
|
||||
# - Failed GE purchases (offer unfilled): re-place at live low + 5% with paced offers
|
||||
# (a4/a5); after 3 consecutive failures, alert + stop (failed) unless a fallback
|
||||
# candidate is switched in — never sit in an unfillable offer loop.
|
||||
# - Staff of fire cannot be equipped (a3): fall back to buying 3 fire runes per cast
|
||||
# (3 fire + 1 nature = 155 gp/cast rune cost vs 140; net -18/cast at the anchor),
|
||||
# log WARN, continue; never loop on equip attempts.
|
||||
# - Invalid loadout (wrong item in hand / spell unavailable): re-run build-loadout (a6);
|
||||
# 3 consecutive failed casts -> failed (stop, log ERROR sentinel, alert).
|
||||
# - Explicit completion/stop: stop_conditions above (Magic 55 HLA handoff, gp floor,
|
||||
# repeated failures).
|
||||
# bank_supplies at candidate OR nature < 100) catches both mid-run depletions; the
|
||||
# restock phase (a10 -> a2 -> a11 -> a12) 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/a12) and the remainder is re-placed at
|
||||
# the current edge (a3/a4/a5/a11); 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): re-run build-loadout
|
||||
# (a8); 3 consecutive failed casts -> failed (stop, log ERROR sentinel, alert).
|
||||
# - 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 HLA handoff, 2 h session
|
||||
# horizon, assets floor 575,150, loss reserve 162,990, repeated failures, fail-closed
|
||||
# staff equip).
|
||||
|
||||
sources:
|
||||
- "OSRS wiki — Low Level Alchemy (level 21, 31 xp/cast, 3-tick, 1 nature + 3 fire; spellbook Normal; infobox 2026-08-27)"
|
||||
@ -332,12 +450,14 @@ sources:
|
||||
- "prices.runescape.wiki latest 2026-08-27, re-fetched at bounce fix (low = per-repo buy basis: rune javelin tips 403, rune arrow 45, nature rune 140, jade ring 303, opal amulet (u) 17)"
|
||||
- "OSRS wiki — Module:Exchange/Rune javelin tips (limit 10000, lowalch 540, highalch 810, members=true — matches mapping; re-verified 2026-08-27) + Module:Exchange/Nature rune, Staff of fire and all cited candidates (GE limits agree with mapping; verified 2026-08-27)"
|
||||
- "OSRS wiki — Rune javelin tips / Rune arrow / Bagged flower / Mystic mist staff etc. item pages (members = Yes for every cited catalog item; verified 2026-08-27)"
|
||||
- "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 — Nature rune (members craft at level 44 Runecraft from pure essence, 9 xp; Nature Altar south-east of Tai Bwo Wannai)"
|
||||
- "OSRS wiki — Abyss (access to runic altars without talismans via the Mage of Zamorak)"
|
||||
- "OSRS wiki — Bryophyta's staff (level 30 Attack + Magic; up to 1,000 nature charges; 1/15 chance to not consume a charge on any nature-rune spell; alchemy combo with Tome of Fire)"
|
||||
- "OSRS wiki — Tome of Fire (members, level 50 Magic to wield; charged tome is an infinite fire-rune source and non-combat spells do not consume charges)"
|
||||
- "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) + verb take_break — the cadence + break + recovery model"
|
||||
- "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, never assumed) — the cadence + break + GE + recovery model"
|
||||
verified: "2026-08-27" # keep quoted (YAML 1.1 date parsing); prices last re-fetched live 2026-08-27
|
||||
|
||||
related:
|
||||
|
||||
@ -41,6 +41,37 @@ def load_entries():
|
||||
return sorted(out)
|
||||
|
||||
|
||||
def alch_worked_example_regression(rel, data, raw_text):
|
||||
"""One-cast model worked-example regression (owner guidance 2026-08-28,
|
||||
PR #8 repair): entries with the owner-selected one-cast iteration model
|
||||
must pin a worked example with MONOTONIC, INDEPENDENT counters — breaks
|
||||
every 550 casts (1,100, 1,650, ...) regardless of restocks, and restocks
|
||||
every 901 casts (1,802, ...), so restocking never resets or shifts the
|
||||
break counter. The old 'restart the interval at the restock' bug (break
|
||||
#2 at cast 1,452 = 901 + restarted 549) must never reappear. Scoped to
|
||||
entries that declare the one-cast model AND carry a worked example, so
|
||||
unrelated entries are untouched."""
|
||||
ruco = data.get("run_control") or {}
|
||||
if "one cast" not in str(ruco.get("iteration", "")):
|
||||
return []
|
||||
if "worked example" not in raw_text.lower():
|
||||
return []
|
||||
errs = []
|
||||
if "1,452" in raw_text:
|
||||
errs.append(f"{rel}: worked example resets the break interval at a restock "
|
||||
f"(cast 1,452 = 901 + restarted interval) — breaks must stay "
|
||||
f"monotonic at 550/1,100/1,650 independently of restocks")
|
||||
for marker, label in (("550", "break #1 (cast 550)"),
|
||||
("901", "restock #1 (cast 901)"),
|
||||
("1,100", "break #2 (cast 1,100)"),
|
||||
("1,650", "break #3 (cast 1,650)"),
|
||||
("1,802", "restock #2 (cast 1,802)")):
|
||||
if marker not in raw_text:
|
||||
errs.append(f"{rel}: worked example missing monotonic counter pin "
|
||||
f"{label} — breaks/restocks must be pinned literally")
|
||||
return errs
|
||||
|
||||
|
||||
def main():
|
||||
global STALE_DAYS
|
||||
if "--stale-days" in sys.argv:
|
||||
@ -99,6 +130,10 @@ def main():
|
||||
if term not in declared:
|
||||
errors.append(f"{rel}: terminal '{term}' not declared")
|
||||
|
||||
# one-cast worked-example regression (owner guidance 2026-08-28):
|
||||
# monotonic break/restock counters, scoped to the one-cast model
|
||||
errors += alch_worked_example_regression(rel, data, path.read_text())
|
||||
|
||||
# action id/step uniqueness
|
||||
a_ids = [a["id"] for a in data["actions"]]
|
||||
a_steps = [a["step"] for a in data["actions"]]
|
||||
|
||||
Loading…
Reference in New Issue
Block a user