030 ひと箱の天気 教材QA
検証日: 2026-10-05 UTC
環境: Linux / Python 3.12.14 / Pyxel 2.9.9 / SDL_AUDIODRIVER=dummy / python -B

結果
- 50 unittest項目。原作を指定したライブ比較は50合格・skip 0。
- 標準ライブラリ単独(-S)は49合格、任意ライブ比較1項目skip。
- 教材一式を日本語/空白パスへコピーし、無関係なCWD・-Sで同じ49合格/1skip。
- 原作Cの手数を除いた全85到達安定状態から4行動ずつ、340遷移を照合。
  04と05のstate、accepted、reason、全trace、全transfersが原作由来fixtureと一致。
- 原作test_model.py由来の合流・余剰・旧K・開門・細管5配置と、
  Cの4ノードへ総量3を置く全20配分、計25microstep配置を照合。
  門2配置×120順列、合流2配置×24順列、計288通りで結果・イベントが不変。
- 保存則、途中のF 3/2、次刻みの余剰、同刻みK到着、1ノード1滴、
  グラフ循環/不明宛先/垂直接触同着の拒否、終息上限エラーを確認。
- 花の水は消費せず回収可能、Kを吸うと閉門、空振り/閉門/余剰はSへ。
- 成功後の通常遷移停止、成功後Undo、全Undo、新しい分岐、無効入力の履歴不変。
- 保持キー、部分解放、Rを含む同時押し、リセット後の全解放、描画の非破壊。
- 実Pyxelの23画面再生を実行し、720×500 PNGとフレーム/時間/状態JSONを保存。
  最低12フレーム、長い再生は2×入力数+2。全受理イベントと途中配列の水量を検証。
- 各.pyを1本だけ日本語/空白ディレクトリへコピーした5回の実Pyxel起動。
  作業フォルダは無関係な別日本語/空白パス。標準入出力cp932。
  画像、原作、他教材、assetsに依存せず成功。合計28回の実Pyxel検証。
- 各5本×7種類、35の不正CLIを-S(Pyxelなし)でexit 2として拒否。
- lessons.jsonの抜粋が配布.pyに完全一致。LESSON.mdの演習をrun_examples.pyで再現。
- 原作MIT全文を各.pyに保持。LICENSEとassets/NOTO-LICENSE.txtは原作と同一byte。
- 原作フォルダ37ファイルのSHA256は作業前後で一致。元作品を変更していない。
- FROZEN_SHA256.jsonは配布ファイルの集合・サイズ・SHA256を記録。

証拠
qa/tests-stdlib.txt: Pyxel・原作不要のテスト。
qa/tests-live-original.txt: 原作モデルを直接読んだ任意比較を含む50合格。
qa/tests-detached-stdlib.txt: 独立コピーした教材を-Sでテスト。
qa/source_fixtures.json: 原作ハッシュ、Cの340遷移と中間配列、25移送配置。
qa/render_runs.json: 実Pyxel23回のフレーム数、論理秒数、実時間、終了コード、状態/ソースhash。
qa/01〜05のPNG/JSON: 各段階の初期と意味ある途中/成功/Undo。
qa/isolation_runs.json: 単独ファイル5本の日本語・空白・別CWD・cp932起動。
qa/cli_invalid.json: 35負例の引数と終了コード。
qa/examples.txt: 本文演習の実行結果。
qa/canonical_before.json、qa/canonical_verification.json: 原作変更なし。
qa/image_inspection.json、qa/contact_01〜04.png: 全23画面の画像確認。
qa/freeze_verification.txt: 配布時の凍結確認結果。

目視
実Pyxelの最終版PNG全23枚を4枚の一覧画像で確認し、05_successと03_old_K_afterは
元解像度でも確認。空き枠は輪郭、所有水は塗りつぶしにし、0/満杯の違いを明示。
図と量の一致、SUN/RAIN、門状態、Fの余剰、Kの旧条件、成功/Undoを確認。
画面端の切れ、主要な文字の重なり、状態に反する水の加算は認めなかった。
原作と同じ画面の模写ではなく、学習用のASCII・状態帳簿つきの別レイアウト。

未検証・主張しないもの
ブラウザー、Windows/macOS実機GUI、ネイティブOSキーボード操作、人の試遊、音の実聴。
教材は無音。合成入力とheadless描画を人の操作と混同しない。
通常Cの有限状態照合は全履歴、独自レベル、原作controller全フレームの網羅証明ではない。
原作controllerの移送4フレーム表示、P/M/N、タイトルは教材から明示的に省略。
原作自体の25テストと元デモの事前再検証は別記録で、上の50テストへ加算していない。

再実行
python -B test_stages.py
python -B tools/run_examples.py
SDL_AUDIODRIVER=dummy python -B tools/run_qa.py
python -B tools/verify_frozen.py
任意ライブ比較: WEATHER_ORIGINAL_MODEL=/absolute/path/model.py python -B test_stages.py

QA再実行は実時間などを更新するため、元の凍結hashとは変わる。
元の配布物確認は先にverify_frozen.py。変更内容を確認した後だけ--writeで再固定。
