013 棚からぼたもち教材 QA
検証日: 2026-10-05 UTC
対象: 原作C「荷重の引越し」、01〜05の独立教材

環境
Python 3.12.14 / Pyxel 2.9.9 / Linux headless
実行Python: /workspace/scratch/2daa2f5630e7/pyxel-howto-pilot/.venv/bin/python
-B、SDL_AUDIODRIVER=dummy。実画面は640×460。

検証結果
- 60 unittest全通過（原作をライブ照合する1件を含む）。qa/tests-live.txt
- 切り離した教材フォルダ: 60件検出、59通過、原作の任意ライブ照合1件をskip。
  安定fixtureと本文例を使うテストは通過。qa/tests-detached.txt
- 原作model.py由来24固定除去経路＋13境界配置を照合。
  最終状態だけでなくFrameのevent/対象ID/状態hashも比較。
  容量一致、片支え、中央支持、同時破断、積み重なりの同時落下、
  固定端がある板、床、板ともち・皿の接触、危険優先を検査。
  全ての操作履歴を網羅した証明ではない。qa/canonical_reference.json
- 入力: heldの反復、全解放ゲート、同時押し拒否、部分解放、Rによる迂回禁止、
  04未解決中の優先順位、05終了後Z/R、描画の状態・履歴非変更。
- 本文例6行と全5段階の練習操作を自動検証。qa/examples.txt
- 実Pyxel headlessを20ケース実行。全段階の初期＋重要チェックポイント。
  合成Controller入力であり、ネイティブOSキー入力でもブラウザ動作でもない。
  最終描画のソースSHA256を各JSONへ記録。qa/render_runs.json
- 実行フレーム数は12/14/26/30、論理時間0.4〜1.0秒（30fps）。
  最終20ケースの個別プロセス実測は0.471499〜1.068042秒。
  論理時間と実測時間を混同しない。長時間の安定性評価ではない。
- 5本を各々単体stage.pyとして日本語・空白入りの別フォルダへコピーし、
  無関係な日本語・空白入りcwdから実起動。兄弟.pyや原作モデル不要。
  cp932標準入出力、UTF-8 JSON出力を検証。qa/isolation_runs.json
- 無効CLIは5本×3ケース=15件、全て終了コード2。qa/cli_invalid.json
- 画像20枚を実画素で確認。04のPENDING表示を追加し、代表7枚を再確認。
  盤面、荷重表示、破断、落下、衝突、成功、Undo、Resetに欠けや重なりなし。
  qa/visual_review.json

原作の再検証と区別
原作30テストと自動デモのfresh結果はqa/original_evidenceに別途同梱。
これらを教材60件へ加算しない。原作model/app/README/権利文書は、
親タスクが検証した原作コピーとバイト一致。qa/provenance.json

権利と独立性
原作LICENSE全文をLICENSEと5本全ての冒頭へ保持。
参照されるassets/NOTO-LICENSE.txtも原文一致。Noto字形データは使わない。
全段階は標準ライブラリ＋起動時だけimportするPyxelで動作する。
qa/rights_packaging.json

再検証
python -B test_stages.py
python -B tools/run_examples.py
python -B tools/run_qa.py
python -B tools/verify_frozen.py
任意ライブ照合は環境変数SHELF_ORIGINAL_MODELへ原作model.pyの絶対パスを設定。
fixtureを作り直す時だけtools/make_reference.pyへ同じパスを渡す。
通常テスト・教材起動・画像再現に原作フォルダは不要。
再実行後は測定時間などの変更で凍結hashが変わるため、内容確認の上で再固定。

限界
現実の構造工学や安全性の検証ではない。回転/滑り/変形なしの架空模型。
ブラウザ、Windows/macOS実機、ネイティブOS入力、人の初見理解・楽しさ、
音の実聴、長時間耐久は未検証。公開作業はこの教材作成タスクでは行っていない。
