fix!(lua): G.GAME state survives menu+start — a previous run's won flag marks later losses as wins

オープン
#232 コメント 0 件 リアクション 0 件 担当者 0 名 GitHub で見る

まだ誰も着手していません。

評価

難易度
4/5
見積もり時間
3〜5日
初心者へのやさしさ
48/100
issue の種類
バグ
明瞭さ
おおむね明確
活発さ
静か
技術スタック
lua, python
領域
api, backend, testing

調査の方向性

start.lua の menu→start パスから始め、次に src/lua/utils/gamestate.lua:739 と play.lua:125 を調べて、won がどのようにシリアライズされ消費されるかを確認します。引用されているアクショントレースまたは repro バンドルを使い、長期間存続する 1 つのインスタンス上で勝利に続いて敗北するケースを再現し、各実行を新しいプロセスのシミュレーターと比較します。4 つの一覧表示された状態フィールドが実行ごとに再構築され、bot.py が敗北を勝利として記録しないことが完了条件です。

索引モデルが issue の本文から書いたものです。

説明

Description

Starting a new run via menu + start on a long-lived instance does not fully
reset run state. We catalogued four distinct cross-run leaks, each confirmed by
replaying the identical action trace on a vanilla-faithful simulator (fresh
G.GAME every run) and diffing the full gamestate after every action.

  1. G.GAME.won — after any win in the session, a later run's GAME_OVER
    loss reports won = true. 16 instances observed; e.g. seed ESVPE7W2: 696
    chips vs Amber Acorn, unambiguous loss, live gamestate won = true — leaked
    from the previous run's ante-8 win on the same instance.
    src/lua/utils/gamestate.lua:739 serializes the raw global
    (state_data.won = G.GAME.won), so the stale value flows straight to
    clients; play.lua:125 also branches on it.
  2. G.GAME.last_tarot_planet — a fresh run's first Fool copied the tarot
    last used in the previous seed's run.
  3. G.GAME.pool_flags — gros_michel_extinct leaked: a run that never
    owned a Gros Michel was offered Cavendish in the shop (seed LS4ECDCB).
    Extinction only rolls for owned jokers at round end, so this is
    vanilla-impossible in-run.
  4. G.GAME.used_jokers key loss (mechanism unidentified, same family):
    live's shop offered j_banner while Banner sat in play (seed LS6VZ3ES) —
    impossible under the no-repeat pool. RNG forensics showed both sides drawing
    identical raw picks from the same stream; the sim resampled per no-repeat,
    live kept the duplicate, i.e. live had lost the key.

Root cause is presumably in how the run is rebuilt through the menu→start path
versus a fresh process launch (possibly SMODS-side), but balatrobot's start
endpoint is the natural place to defend against it.

Impact

This corrupts benchmark results, not just convenience:

  • balatrollm runs its whole task list through long-lived instances (the
    executor's port pool starts instances once) and starts each run with
    menu+start. bot.py ends a run as won when gamestate["won"] is truthy — so
    a loss that occurs on an instance after that instance has produced any win can
    be recorded and published as a win (run_won in the leaderboard data and
    the CC0 dataset).
  • Leaks 2–4 make seeded runs non-reproducible: shop and consumable outcomes
    depend on what earlier seeds did in the same instance.

Suggested Fix

In start.lua, after the run initializes, explicitly reset the leak-prone keys:
G.GAME.won = false, clear last_tarot_planet, and verify pool_flags /
used_jokers are freshly built. Alternatively (or additionally), document that
benchmark-grade data requires one process per run.

Repro bundles (action trace + both gamestates + field diff) available for every
seed cited.

主要言語
Python
スター
80
フォーク
23
PR マージ指標
30日以内にマージされた PR はありません

環境構築

はじめの一歩

  1. issue を最後まで読み、次にプロジェクトのコントリビューションガイドを読みます。
  2. 着手することを issue にコメントします — 二人が同じ作業をするのを防げます。
  3. リポジトリをフォークし、ブランチを切って変更します。
  4. issue 番号を参照したプルリクエストを送ります。

coder/balatrobot のほかの issue

coder/balatrobot の issue をすべて見る

似ている issue

Python の issue をもっと見る

新しい issue をメールで受け取る

初心者向けの GitHub issue を短くまとめたダイジェスト。