014 教材 新規QA（2026-10-05 UTC）

対象と主張
原作B「横切る岩」だけ。04/05の物理は原作Bの規則・単位・順序を保持。
05では残したSPACE開始/R/P/Z/方向/掃除も原作appとの合成入力比較を実施。
01は掃除のみ、02は通れる期限付き線、03は岩のない自分の壁という教材用ルール。
原作3面全体、面選択/N/F12/録画/日本語UIの同値性は主張しません。

今回の結果
- 5本のPythonは互いにも原作にも依存しない単独実行形式。
- 実行時の外部依存はPyxel2.9.9だけ。import pyxelはmain内、モデルは標準ライブラリのみ。
- Python3.12.14 / Pyxel2.9.9 / Linux / SDL_AUDIODRIVER=dummy / -B。
- test_stages.py：54テスト合格。qa/model_tests.txt。
- 配布フォルダーだけを日本語・空白パスへコピーし、無関係なCWDから-B -Sで54テスト再合格。
  site-packages/Pyxelなしの再実行です。qa/standalone_tests.txt。
- 原作から新規生成した6軌跡、計4688物理tickを04/05両方で全状態hash比較。
- 69の寿命/離脱/猶予/岩/同時成功・衝突境界の前後状態を04/05で比較。
- 120のカプセル幾何ケースを03/04/05で比較。
- 原作appをPyxel stubで読み、残した操作617入力frameを05で比較。
  位置だけでなく状態hash、タイトル、停止、巻戻し回数、全履歴hashを照合。
- 同じ146入力frameでwall_enabledだけを変える追加対照実験。
  原作同様、壁なしはcollision、壁ありはplaying。04/05の全入力frameの状態hashが一致。
- 01〜03の成功経路は原作B成功時の位置・時刻・回収・移動距離等の投影と一致。
- tools/verify_original.pyで現行の原作を再読込し、保存fixtureの全内容と一致。
  qa/live_original_comparison.txt。JSONのtuple/listは保存形式に正規化して比較。
- 原作フォルダー36ファイルの一覧と全SHAが開始時と一致。qa/original_unchanged.json。
- CLI不正入力11種類×5ソース=55件が、Pyxel import前に終了コード2/Tracebackなしで拒否。
  負数/小さすぎる/大きすぎるframe、headlessなしQA出力、競合demo/replay、不正JSON/型/キー、
  見つからない入力ファイル、不明オプション。qa/cli_invalid.json。
- 各段階をsingle.pyという1本だけにして日本語・空白のパスへコピー。
  別の無関係CWDから実Pyxel headlessを20回実行。全回終了コード0。
- 各段階で無入力12frame、掃除中70frame、成功後145frameを取得（計15枚）。
  追加で所有者壁に停止、壁期限切れ、P停止、Z巻戻し、岩接触を取得（計5枚）。
- 無入力12frameでも01〜04は時計と岩が進むためage0.4秒。05タイトルのみage0。
- この20回では実測入力frameは要求値と一致。将来の更新/描画の同数性は保証しません。
  requested_framesとactual_framesを個別保存し、実測回数で再入力した純モデルsnapshotと全件一致。
- qa/render_runs.jsonはソースSHA、実測frame、入力、PNG、report、ログを対応付けます。
- 全20PNG（790×477）の実ピクセルをview_imageで確認。
  初回観察で終端バナーが岩に重なったため盤面外へ移し、20回を再実行して最終画像を再確認。
  星くず・経路・所有者壁の白い粒・岩の方向矢印・接触輪・停止/巻戻し値に欠落や文字切れなし。
  qa/image_inspection.jsonに画像SHAと観察内容を記録。実画像の合成入力であり人間の試遊ではありません。
- draw_boardはどの状態でも状態を変更せず、数値描画引数は有限、全文字は画面内。
- lessons.json全snippetは該当ソースに完全一致。4差分は現ソースからの再生成と完全一致。
- LICENSEとassets/NOTO-LICENSE.txtは原作とバイト一致。全5段階の冒頭に原作MIT全文。
- FROZEN_SHA256.jsonは自身とqa/freeze_verification.txtを除く配布全ファイルのSHA-256。
  tools/check_freeze.pyは不足/追加/改変を検出する読取専用の検証器。原作やPyxelは不要。

重要な境界と演習
- 42px/s×1/120秒=0.35px/tick、1入力frameは4tick=1.4px。斜めも同速。
- 掃除半径5pxは移動線分からの距離。静止掃除は足元だけで、長さ0の区間は追加しない。
- 区間は2pxまで。同一直線・同方向・連続端点だけ延長し、bornを更新しない。
- ageを増やしてから2.4秒の期限切れを除く。生成直後から288tick後に消える。
- leftは更新開始位置が線から4.02pxを超えたときにTrue。一度Trueになれば戻さない。
- 所有者に有効なのはleft=Trueかつ生後0.18秒以上。足元で待つだけではleftにならない。
- 自分の当たり半径は3+1=4px。線へ戻れば止まるだけで失敗しない。滑り・反射はしない。
- 線分側面と端点の円の掃引。等時刻の法線を整列/重複除去/合成して順序依存を避ける。
- 同じtickで新しく追加した線を、岩の衝突対象へ入れる。岩はleft/GRACEを参照しない。
- 岩半径5+壁半径1。反射は速度の大きさを保持し、接触後の残り時間も進める。
  接触後の法線補正は自分0.001px、岩0.01px。4接触後の残りは原作同様に打ち切る。
- 岩と自分は相対掃引。最後のごみを拾っても同tickの岩接触ならcollisionが優先。
- 期限切れは自分にも岩にもそのtickから無効。clear/collision後はageを含む全状態が停止。
- タイトルSPACEはその入力frameで移動しない。解除待ちはなく、次frameの保持は掃除になる。
- 本編はR>P>停止中>Z>終端>通常更新。Pで全時計停止。停止中Zは無効。
- 通常frameの前をdeepcopy、最大150件。Zは30件前へ戻し、短ければ開始時まで。
  壁のborn/left、ごみ、岩の速度も戻る。巻戻し回数は巻戻し対象外。Rで回数も0。

未検証と限界
人間の試遊、実OSのキーボード、ネイティブGUI操作、Windows/macOS GUI、ブラウザー、音の実聴。
音は未実装。新規OS別pipインストールは未実行。READMEの導入手順と既存環境QAは別です。
原作既存の25試験や媒体をこの教材の54試験/20描画の新規合格数へ加算していません。
保存fixtureは有限のケースで、全入力/全実数に関する形式的証明ではありません。
日本語説明と英語実行画面は意図した構成。日本語字体ファイルは実行時に不要です。
