Commit Graph

21 Commits

Author SHA1 Message Date
Claude
dfa7e00bd0 Merge origin/main into issue-3; bounce-fix 4: executable axe preparation, per-selected-row dynamic rates, drop-GP-zero (governor 10398, owner decision 10499)
- woodcutting-f2p.yaml v5: prepare state (a2-a9 check/withdraw/GE-buy/wait/collect/equip-or-carry/loadout -> travel), unobtainable axe -> failed (never complete), chopping->drop_logs gated to afk-xp, per-row chop/walk/respawn/log_price constants, mode rates = canonical top-row reference, woodcutting_fixtures (level-1 / level-50 quest+no-quest / level-70 / level-30 profiles), drop-mode realized GP 0
- schemas/entry.schema.json: ladder rows require per-row rate fields; model slimmed to drop/deposit/break; woodcutting_fixtures block added
- tools/validate.py: port woodcutting gates onto the economy validator (select_ladder_row + row_rates recompute fixtures at 27/28 capacity, drop-GP-zero gate, prepare/failed/drop-gating wiring checks); selftest now 55 checks
2026-08-29 04:53:03 -05:00
Claude
d19a4d9de0 Merge remote-tracking branch 'origin/main' into issue-1
# Conflicts:
#	tools/validate.py
2026-08-29 03:13:45 -05:00
Claude
671d025d9f fix(flip-candidates): release the physical GE slot after a completed flip via closed -> free (governor 10471)
A successful sell followed sell-filled-awaiting-collect -> closed, and
'closed' had no outgoing transition while the scheduler left closed
slots untouched — every GE slot could perform ONE flip and then became
permanently unusable (no rotations, breaks, or longer sessions).

Fix (finding-by-finding, governor comment 10471):
1. 'closed' is no longer a sink. The completed cycle's ledger is
   reconciled and ARCHIVED at close, and the physical slot is released
   to free via the explicit archival transition closed -> free
   (flip-candidates.yaml slot_transitions, whens, scheduler_iteration,
   a9 archive step, summary, risk, sources). The scheduler pass
   dispatches the release (SLOT_DISPATCH['closed'] = 'release'), so a
   closed slot is only ever transient.
2. A deliberately closed cancelled sell releases identically:
   sell-cancelled-awaiting-collect -> closed -> free (whens updated).
3. Committed two-rotation regression (validator, wired into
   ge_lifecycle_errors for every flipping entry): slot_reuse_violations
   walks one physical slot through free -> buy-open ->
   buy-filled-awaiting-collect -> ready-to-sell -> sell-open ->
   sell-filled-awaiting-collect -> closed -> free -> buy-open (second
   buy in the SAME slot), validating every ledger frame against both
   conservation gates; archived_ledger_preserved_after_second_buy
   proves the rotation-1 archived ledger survives rotation 2 bit-for-bit
   (no loss, duplication, or mutation). Negative fixtures prove a
   closed sink or a closed that does not release to free FAILS.
4. ge_lifecycle_errors now requires closed == ['free'] exactly and
   rejects any machine where a state has no transitions.
5. Worked example: t5/t8 walk the release, t8b runs rotation 2 in the
   same physical slots.

All prior fixtures preserved (tax x4, async-slot scheduler,
collection-box, limit-window, side-aware conservation x25) — now 35
selftest checks.

Evidence: python3 tools/validate.py -> 2 entries, 0 errors, 1
pre-existing warning; --selftest -> 35 PASS, 0 errors; git diff
--check clean.
2026-08-29 03:11:20 -05:00
762a8bb608 Merge pull request 'Codex entry: low alchemy — members (loss-minimizing) (Closes #2)' (#8) from issue-2 into main 2026-08-29 10:06:04 +02:00
Claude
052c6984ac codex: low-alch-members — loss-reserve stop direction + fill-price scenario GP bounds (bounce-fix attempt 5)
Owner guidance 2026-08-29 for governor review 10361 (PR #8), finding by finding:

1. Loss-reserve stop direction — the stop read 'session net loss (total
   assets - initial capital) > 162,990'; a loss makes that LHS negative so
   it could never exceed the positive reserve (the stop could never fire).
   Now expressed everywhere as 'initial capital - total assets > 162,990'
   (stop_conditions, worked-example step 6, recovery block, version pin):
   a loss makes the difference positive, the strict-greater comparison
   fires on losses and never on profits, and exactly-at-boundary does not
   fire. tools/validate.py gains alch_accounting_regression(): comparator
   boundary fixtures (below 162,989 / at 162,990 / above 162,991 / profit
   side +50,000 / breakeven) plus entry-text pins rejecting the reversed
   form anywhere in the file.

2. Fill-price scenarios for realized GP bounds — previously gp_per_hour_low
   /high derived only from the live-low -3.00/cast margin while the buy
   policy permits live low + 5% (candidate 423.15 + nature 147 = 570.15 vs
   540 lowalch = -30.15/cast). The economy block now declares FILL-PRICE
   SCENARIOS A (live-low 543 -> -3.00/cast) and B (max allowed +5% 570.15
   -> -30.15/cast) as the single ledger behind capital, batch economics
   AND the GP bounds: gp_per_hour_low -29,463 (scenario B x session-fast
   977.2), gp_per_hour_high -1,758 (scenario A x session-slow 585.9),
   midpoints -22,365 / -2,225 pinned; validator enforces the exact bound
   values and the -30.15/570.15/423.15 scenario pins.

Preserved: complete GE acquisition/restock flow, one-cast iteration,
monotonic break/restock counters, total-assets accounting (floor
575,150), fail-closed staff path, and the earlier fixed pacing/equip
findings. version 5 -> 6, updated 2026-08-29.

Gate: python3 tools/validate.py -> 2 entries, 0 errors, 1 pre-existing
F2P WARN (low-alch-f2p researched, untouched); git diff --check clean;
regression negative-tested (old gp pins, reversed form, missing scenario
pins all rejected).
2026-08-29 03:00:56 -05:00
Claude
76f8e5ad27 fix(flip-candidates): GE asset accounting + offer lifetime per governor 10390 (bounce-fix 6)
- Buy-limit reset NEVER cancels an offer: quote_age_policy now aborts
  only on a stale scanned edge or explicit strategy reallocation; the
  4h window is a capacity clock (limit_ledger), not an offer deadline.
  Removed every lapse-as-cancel trigger from best_practice, whens,
  quote_age_policy, a5/a8, worked example, risk, and the a6 verdict.
- Completed offers pass through the collection box: new canonical
  sub-states buy-filled-awaiting-collect / sell-filled-awaiting-collect;
  a full buy cannot sell and a full sell cannot close before ge_collect
  (scheduler dispatches collect for all four *-awaiting-collect states).
- Works the arrowtips example side-aware: a 4,000/10,000 partial BUY
  cancel returns 4,000 units + refunded CASH for the unfilled 6,000 —
  never 'refunded units'; the phantom 10,000-unit withdrawal is gone.
- conservation_violations() is now side-aware (buy: quoted =
  filled + still_open + cancelled_unfilled with acquired items = filled
  only, cash = spent + still_committed + refunded; sell: quoted =
  sold + still_open + returned_unsold) with slot_phase_violations()
  phase gates and committed negative fixtures: phantom refunded buy
  units, a full buy sold before collection, a full sell closed before
  proceeds collection. Existing tax/scheduler/limit fixtures preserved.
- grammar (ge_cancel/ge_collect), schema sub_states minItems, entry
  version 5 + sources updated accordingly.
2026-08-28 14:48:55 -05:00
Claude
86c0c896d8 woodcutting-f2p: three explicit modes + corrected axe model (governor 10323 bounce-fix 3, owner decision 10288)
- fast-xp / afk-xp / banked-income modes with deterministic first-match
  ladders (no 'or'), level-1 fallbacks, pinned activity state
- axe model corrected: 41 Woodcutting to USE / 40 Attack to EQUIP;
  equip only when Attack permits, else carry the same axe — committed
  axe_examples incl. the 1-Attack/41-WC rune-axe carry case (owner)
- full per-mode lifecycle: prereqs, axe acquisition, initial inventory,
  travel, depletion/respawn, one chop attempt, inventory-full, complete
  dropping or banking route, breaks independent of incidental banking,
  recovery branches, completion
- per-mode worked examples: prep -> first full-inventory boundary ->
  first scheduled break -> resume (level-50 and level-70 pinned)
- realized rates: logs/hr = model chain (chop x capacity / cycle incl.
  walk/deposit or drop, x respawn duty x break duty); xp/gp derived
  and validator-enforced (axe_tiers / axe_examples / woodcutting_modes
  structured schema blocks + 16 committed selftest fixtures)
- wiki-verified axe table 2026-08-28; prices refreshed 2026-08-28
2026-08-28 04:21:31 -05:00
Claude
02b366c7ef flip-candidates: per-slot async sub-state lifecycle (governor 10323 bounce-fix 5)
- slot_state_machine: canonical 8 sub-states (free/buy-open/
  buy-cancelled-awaiting-collect/ready-to-sell/sell-open/
  sell-cancelled-awaiting-collect/ready-to-requote/closed) + global
  scheduler pass that never advances unrelated slots
- ge_cancel moves filled items/refunds/unsold units/coins to the GE
  collection box; ge_collect + ledger reconciliation before reuse
- 4h buy-limit ledger (limit_used/first_fill_ts/limit_resets_at) distinct
  from offer expiry; cancellation never renews the limit
- per-slot conservation invariants w/ committed validator fixtures
- economy.ceiling_gp_per_hour typed ceiling, gp_per_hour_low/high as
  documented realized scenario bounds (no uncited multipliers)
- capped/floored 2% tax + 4 fixtures preserved (owner decision)
- action-grammar: ge_cancel/ge_collect rows corrected
2026-08-28 04:01:20 -05:00
Claude
a197b34aa8 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.
2026-08-28 03:36:45 -05:00
Claude
3572255a11 codex: complete GE-flip lifecycle per owner addendum — partial fills, ge_cancel recovery, ledger, break/resume, realized rates (bounce-fix 4)
Owner lifecycle addendum (2026-08-28) + governor bounce 4 (lifecycle contract):
- state machine now covers the ENTIRE buy -> sell -> collect flow with no
  stranded state: partial fills tracked per slot (filled_qty ledger), 4h-lapse
  buys go to a new cancel_requote state (ge_cancel: units return to inventory,
  cash refunds, slot freed) instead of collect, cancelled units still sell at
  the high edge, lapse sells re-quote or lower rather than strand
- action grammar + schema extended ONCE with the cancellation mutation
  ge_cancel (was missing; ge_clear/ge_offers_done are predicates only) and
  used explicitly in the new a8 cancel-requote action
- concrete runtime state: minimum per-slot capital table (buy x 4h limit),
  members 8-slot vs F2P 3-slot paths, per-slot offer phase + quantities,
  buy-limit window, inventory/collection reconciliation in a9
- breaks connected to an explicit safe/resume path: resting offers persist
  server-side + per-slot ledger survive the pause; resume = re-open GE,
  re-check offers, continue current phase; never break mid-collect/mid-place
- rates qualified against the full lifecycle: 149,500 gp/h is named the 4h
  buy-limit CEILING; realized range = ceiling x fill_factor (~0.5-0.9) x
  duty_cycle (~0.90-0.95) ~ 96,300 gp/h midpoint; gp_per_hour_low 74,750
- pinned worked example: capital 22.5M -> 8 slot quotes -> arrowtips partial
  fill (4,000/10,000 tracked) -> iron bar full fill sell (90,000 net) ->
  cosmic no-fill ge_cancel + requote -> arrowtips partial matures at lapse
  (cancel, sell 4,000, 68,000 net) -> first break after 6-10 rotations ->
  resume -> stop conditions
- version 2 -> 3; evidence: validate 2 entries 0 errors 1 pre-existing WARN,
  selftest 4 PASS (fractional-tax fail, ge non-margin pass, floored pass,
  above-cap pass), synthetic merge main 79cab78 + head clean + gate green,
  git diff --check clean
2026-08-28 03:19:13 -05:00
Claude
5ddfc6cdbc codex: repair low-alch-members break/iteration model per owner guidance (bounce fix attempt 3)
- iteration = one cast; break.every = [400, 700] COMPLETED casts, cast-count
  based and independent of bank visits (owner decision A) — bank-cycle claim removed
- numeric carried_batch 1,000/1,000 + restock_threshold 100 -> deterministic
  restock trigger; first restock at cast 901 (worked example pinned)
- full runnable lifecycle in actions: reach-bank, buy-staff, equip-staff (with
  fire-rune fallback failure path), buy-supplies, buy-natures, build-loadout,
  cast-alch (exact consumption + coins), restock, take-break
- rates now REALIZED incl. setup/restock/breaks: xp_per_hour 24,500,
  gp_per_hour -2,960..-1,980; loop-only 837/hr derivation still pinned
- pinned worked example: pre-inventory -> break #1 @550 -> first restock @901
  -> resume @902 -> break #2 @1452 -> restock #2 @1802
- staff of fire equip requirement wiki-verified 2026-08-28: none documented
  (infobox + prose silent vs Battlestaff's 30 Attack/30 Magic)
- version 3 -> 4; validator 2 entries 0 errors (1 pre-existing F2P WARN); Closes #2
2026-08-28 02:56:53 -05:00
Claude
368734da65 codex: fix woodcutting-f2p entry per governor review (bounce fix attempt 2)
- Dragon Slayer I removed from accounts.requires_quest (empty for the
  base entry); it now gates ONLY the optional Maple tier (a1 tier gate,
  a2 maple route, idle transition)
- Dynamic inventory: no hardcoded 28-log assumption — equip the axe only
  when the Attack requirement is met (rune/gilded = 41), otherwise chop
  with the axe carried (27 log slots); inventory-full derived dynamically;
  banking deposits logs ONLY, axe preserved
- version 2 -> 3
2026-08-27 17:06:15 -05:00
Claude
284ec17370 codex: fix low-alch-members pacing model per governor review (bounce fix attempt 2)
- anti_ban.delay is additive to the 1.8s cast (action-grammar.md:135):
  cycle = 1.8s + 1.6-3.4s = 3.4-5.2s, midpoint 4.3s -> ~837 casts/hr
- xp_per_hour 44,640 -> 25,953; gp_per_hour range -3,177..-2,077;
  formula pinned in economy pacing block and actions a3 comment
- run_control.iteration = one full inventory+bank cycle (break.every
  counts iterations per docs/schema.md), bank-cycle claim removed
- risk note cadence pin updated; version 2 -> 3
2026-08-27 16:49:41 -05:00
Claude
8a8cc0d6b3 fix(codex): F2P maple path, XP/income mode, executable bank loop, combat gate (issue #3)
Governor-review bounce (PR #12) fixes on issue-3:

1. Maple IS F2P — restored as an optional level-45 tier. The only F2P
   maples are the 4 trees in the Corsair Cove Resource Area (requires
   Dragon Slayer I to enter), per the Free-to-play Woodcutting training
   guide and Maple tree page (members1=No @ Corsair Cove). Entry no
   longer labels Maple itself members-only; the quest gate is in
   accounts.requires_quest and the tier route table.

2. XP-versus-income mode is now explicit: state machine and a1 gate-tier
   take a mode parameter — XP mode stays on Willow (or Maple with Dragon
   Slayer I) after 60; income mode selects Yew at Edgeville. The guide:
   yew logs 'earn a profit' but 'it is recommended to cut willow or
   maple trees for experience'. Default is XP mode; income must be an
   explicit run parameter.

3. Bank loop is now executable and tier-specific: actions split into
   walk-to-bank (a5) + deposit-logs (a6) + walk-back-to-trees (a7), and
   the state machine pins chop -> walk_to_bank -> deposit_logs ->
   walk_back -> chop with dedicated states. Per-tier tree+bank routes
   (Lumbridge/Draynor/Edgeville/Corsair Cove) replace the hardcoded
   Draynor-for-everything; Yew is routed to Edgeville (guide: 'best
   place to chop yew trees is south of Edgeville bank').

4. Combat gate instead of a false no-combat claim: the Draynor willow
   spot sits between two aggressive level-7 Dark Wizards that attack
   players under combat 15 (Draynor Village wiki page). Accounts below
   combat 15 are routed to the single Edgeville willow (bank adjacent);
   relog/respawn N/A now scoped to the gated routes only, and the risk
   notes call out Draynor as a combat zone for low-level accounts.

Tests: python3 tools/validate.py -> 2 entries, 0 errors, 1 pre-existing
warning (researched flag on low-alch-f2p, owned by issue #5's PR);
merged-tree check (main 79cab78 + head) keeps the issue-6 catalog,
gate clean; git diff --check clean.
2026-08-27 12:55:50 -05:00
Claude
31a23a0214 codex: fix low-alch-members entry per governor review (bounce fix attempt 1)
- Pacing: 3-tick cast is 1.8s (0.6s/tick), not 5.4s; xp_per_hour and
  gp_per_hour now derive from the mandatory anti_ban.delay [1600, 3400]ms
  pause (2.5s midpoint -> 1,440 casts/hr -> 44,640 XP/hr), arithmetic pinned.
- Anchor: model the actual least-loss liquid candidate, rune javelin tips
  (id 19580, -3/cast live, limit 10,000, lowalch==highalch*2//3 asserted);
  top-10 margin list re-fetched live; sign errors in old caveat fixed
  (opal amulet (u) stale-low artifact disqualified, jade ring now
  marginal-profit and flagged as flip candidate, not the anchor).
- Bryophyta's staff + Tome: document the 30 Attack equip gate; accounts
  below it keep the ordinary Staff of Fire path (default, no Attack req).
- version 1 -> 2. Validator: 0 errors (1 pre-existing F2P WARN).
2026-08-27 12:42:02 -05:00
Claude
864f2c9e1c fix(flip-candidates): floor GE tax to whole coins, pin full sell-cycle, qualify F2P path
Governor-review bounce (PR #7) fixes on issue-1:
1. GE 2% convenience fee rounds DOWN per item: net = sell - floor(0.02*sell) - buy.
   Anchor net 16.12 -> 17 (244-4-223); top-8 members table recomputed with
   floored tax -> 598,000/4h = 149,500 gp/h (was 138,000); gp_per_hour_low/high
   updated. Validator now rejects fractional-tax arithmetic for GE-margin entries.
2. State machine split wait_fill into wait_buy_fill / wait_sell_fill so the full
   buy -> buy-fill -> sell -> sell-fill -> collect path is explicit; sell cycle
   can no longer loop back into sell without collecting.
3. Economy qualified as the members path (8 slots); F2P path added (3 slots,
   F2P-tradeable rows only): Iron bar + Cosmic rune + Silver ore = 227,000/4h
   = 56,750 gp/h. Members/F2P flags cross-checked against wiki item pages.
2026-08-27 05:27:09 -05:00
Claude
0ba4646296 codex: woodcutting (F2P) entry
Verified against OSRS wiki 2026-08-27 + live prices:
- F2P tree ladder: Tree 1/25xp, Oak 15/37.5xp, Willow 30/67.5xp,
  Yew 60/175xp (wiki tree-page infoboxes + F2P location lists)
- Issue draft corrected: '45 Pine' disproven (OSRS pines are scenery
  only, Pine tree page); level 45 is Maple (members) — noted in handoff
- F2P axes verified from wiki axe table + item pages: Bronze(1)..Rune(41)
  + Gilded(41) all F2P; Rune axe = best F2P; Dragon = members
- economy anchored on Draynor Village willows: live log sell prices
  (willow 21, yew 112), xp/hr grounded in wiki per-log XP (hourly
  rate explicitly flagged as estimate)
- bankside spot chosen per Oak/Willow/Yew page location lists; tree
  fall timers cited (willow 30s, yew 114s)
- N/A relog/respawn noted (no combat/death vector)

validate.py exit 0 (0 errors). Closes #3
2026-08-27 03:31:01 -05:00
Claude
9651691e9f codex: F2P alch catalog dataset (machine-readable)
Generated 2026-08-27 from prices.runescape.wiki mapping + latest:
filter lowalch != null, members=false, GE limit >= 150 -> 303 items,
sorted by buy price asc. Columns: item, id, buy (latest.low), sell
(latest.high), limit, lowalch_price, value, net_per_cycle
(= lowalch_price - buy). Source of truth for least-loss ranking
referenced by low-alch-f2p / low-alch-members (related: f2p-alch-catalog).

Validator already skips underscore-prefixed dataset files (verified:
exit 0, file not counted as an entry).

Closes #6
2026-08-27 03:22:50 -05:00
Claude
587da06ef0 codex: members low-alchemy entry (loss-minimizing)
Live-verified 2026-08-27 against prices.runescape.wiki mapping/latest
(members catalog: lowalch != null, members=true, 3232 tradeable items)
plus OSRS wiki spell infoboxes and Module:Exchange limits.

- Same state machine + actions as low-alch-f2p (golden template)
- Top-10 least-loss members candidates in economy.profit_drivers
- Handoff note verified from LA page: switch to HLA at 55 (hard level
  gate + strictly more coins and xp per cast); Superheat Item (43) is
  a smithing production spell, not the magic-XP handoff
- best_practice: staff of fire, noted items, Bryophyta's staff + Tome
  of Fire combo, self-crafted natures via Abyss; every line sourced
- accounts: membership members, min_level 21

Closes #2
2026-08-27 03:19:52 -05:00
Claude
04a4af0299 codex/economy/flip-candidates.yaml: GE flipping entry (epic #1 P0 backlog)
Implements the epic's uncovered P0 economy backlog item (flip candidates).
Verified source chain 2026-08-27: prices.runescape.wiki mapping + latest,
all 15 shortlist limits cross-checked against Module:Exchange (agree);
GE tax verified at 2% since 2025-05-29 (1% at 2021 intro), 5M/item cap,
sub-50gp effectively untaxed; Merchanting + Grand Exchange/Buying limits
pages cited for mechanics. Net model: 0.98*sell - buy at band edges.
Gate: python3 tools/validate.py exit 0 (2 entries, 0 errors, 1 pre-existing
warning on the golden entry's researched flag — none added by this entry).
2026-08-27 03:15:59 -05:00
Vale
986fc1a6a8 Codex skeleton: schema contract, action grammar, data-sources rules, JSON schema, validator, golden example (low-alch-f2p, wiki+price verified), README 2026-08-27 02:59:55 -05:00