054 地下商人の帰還 / 五段階教材QA / 2026-10-05 UTC

環境
  クラウドLinux、Python 3.12.14、実Pyxel 2.9.9。既存環境を使用しインストールなし。
  配布仕様はPython 3.11以上。3.11の構文互換をastで検査したが、3.11実機は未実施。

規則・Controller・文章
  qa/full_tests.txt: 52テスト成功。うち任意の原作直接比較1件を含む。
  qa/standalone_tests.txt: 外部原作なしの配布コピーで51成功、任意比較1件skip。
  qa/cp932_tests.txt: pathlibの既定テキスト読書きをCP932に差し替え、51成功＋1skip。
  CP932模擬はWindows実機の実測ではない。
  qa/initial_tests.txtは追加課題テスト前の45成功＋1skipという途中記録。最終件数はfull_tests。

検査内容
  四枠保持、空枠の再販売、不正入力の形・型・負/範囲外番号・bool拒否、全C/M/O相性、
  左右端の回り込みなし、空枠越し/連鎖なし、重複加算なし、道具0金、売却順で6と2の違い、
  毎回の再計算、古い状態不変、価格関数の境界、休憩所交換の回数制限なし、市場交換の拒否、
  同一交換の拒否、帰還時の残荷物維持、9/10金の境界、終端凍結、積載/置換/返却と箱順序、
  ID重複拒否、仕入れの在庫/空枠/金額/滞在先、売上−仕入額の帳簿、15金の帰還を確認。
  Undoは全状態・全取引・帰還も対象。拒否操作では履歴不変。購入取消で在庫とpaidも復旧。
  実App.controlへの合成入力で全段階デモ、長押し/解放、同時入力、R優先、カーソル循環、
  LEFT+RIGHT拒否→LEFTを保持して新たにZを押す回帰と、部分解放/全解放後の再受付を確認。
  pressedだけでなくheldの複数キーも拒否。拒否後は全解放を待ち、ゲート中のRも待機。
  全解放後の入力待ちではR+ZのRを優先し、リセット後も解放待ちになることを全5本で検査。
  交換元の指定/取消、取消をUndoより優先、終端とR、売却/交換予告の副作用なしを確認。
  各課題は価格表変更、実際に変更した段階02の独立ソース、段階03の取消後8金帰還、
  金不足の実Controller、購入→Undo→再購入を確認。全段階描画のASCII境界と不変性も検査。
  本文抜粋が実コードと一致、JSON必須欄、4差分の完全一致、MIT全文、UTF-8 I/Oを検査。

原作との対照
  fixtures/canonical_c.json: 原作Cモデルで生成した16トレースとすべての中間状態。
  正常15金/交換なし13金/道具先売り/空帰還/持ち帰り/置換/重複/金不足/満載/売切/
  市場違い/phase拒否/磁石/二つのきのこ/不正入力/終端の各経路を含む。
  04/05の9フィールドは毎段階で一致。通常テストは同梱fixtureだけを使うため外部依存なし。
  任意の直接比較では、原作Cの全1961出発配置×49行動を04/05それぞれ比較。
  合計192178遷移比較。さらに固定seed 240本×64操作×2段階=30720遷移比較。
  直接比較の総数222898。全出発配置は網羅したが、旅の全到達状態を網羅したとは主張しない。
  対象はC・通常隣接のみ。A/B、wide、原作UI/保存/再現検証の同等性は対象外。
  原作は-Bで読み取り専用import。model/app/README/LICENSEのSHA-256はPROVENANCE.jsonに記録。
  原作側21テストと自動デモは親作業で確認済みだが、この教材の成功件数には含めない。
  原作app.py update（69〜101行）のfresh/downとgateを再読。原作は通常移動/確定で
    一律の複数キー拒否をしない。教材の単発制約は独自UI方針であり原作入力の同等性を主張しない。

実Pyxelによる描画と隔離
  qa/render_results.json: 初期5本、到達点5本、05の灯売却前予告1本の計11プロセス成功。
  qa/isolation_results.json: 各.pyだけを日本語と空白入りの独立フォルダーへコピー。
    無関係なcwdから実Pyxelで起動し、合成Controller入力で意味ある到達点まで5本成功。
    原作/前段階/画像/フォント/ネットアクセスは不要。
  追加のqa/chord_results.jsonは実Pyxel内で保持キー回帰を各段階13入力、5プロセスで検証。
    各*_chord.jsonにpressed/held・解放ゲート・全状態の毎入力記録。拒否の間は不変、
    全解放後の単独Zだけが売却/積載を確定する。tools/render_chord_regression.pyが再現用。
  計21枚のPNGを確認。元の16枚は再実行後も確認済みhashと一致し、追加5枚を開いて確認。四枠、品ID、空枠、相場、加算、メニュー、結果、Undo数、
    05の6 > 2予告に重なり・文字欠けを認めなかった。qa/visual_review.jsonに画像別記録。
  01は2金と1番空。02は灯が空・C売値2。03はWON10金。04/05はWON15金、道具だけ残る。
  実エンジンでdraw/updateした証拠。入力はApp.controlへ渡した合成キー集合であり、
    OSキー入力、人の操作、ネイティブGUI試遊を行った証拠ではない。
  SDL_AUDIODRIVER=dummyを利用。音声確認とは扱わない。この教材は音を定義しない。

権利・固定
  原作LICENSE.txtを無変更でLICENSEへコピーし、五段階先頭にも全文をコメント化。
  原作の著作者名を補っていない。Noto例外注記も原文のまま。字形データは配布しない。
  sourceデータとライセンスの出典はPROVENANCE.json。全教材ファイルの固定hashはFROZEN_SHA256.json。
  原作と公開サイトは編集せず、教材フォルダー内だけで作成・検証。

未確認
  人の面白さ/理解度評価、OS入力・ウィンドウ操作、Windows/macOS実GUI、Python3.11実行、
  ブラウザー実行、音声再生。READMEの各OS起動案内は実機成功の主張ではない。

入力不具合の修正記録（2026-10-05 UTC）
  初版はlen(pressed)だけを検査し、以前から保持したLEFTと新しいZの組を受け付けた。
  5段階すべてをheld判定と拒否時の解放ゲートで修正。README・LESSON・metaにも方針を明示。
  再検証後の正確な変更/追加ファイル一覧はqa/chord_fix_report.json。
  qa/pre_chord_fix_manifest.jsonは修正前版の比較用記録。現在の固定版は根のFROZEN_SHA256.json。
