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:
Claude 2026-08-28 03:36:45 -05:00
parent 5ddfc6cdbc
commit a197b34aa8
2 changed files with 266 additions and 111 deletions

View File

@ -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:

View File

@ -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"]]