080 予報士の机 / 教材QA

検証範囲
原作080-v1.0.2、状況C（LEVELS[2]）の公開8枚・seed757・復元抽選3日。
原作の非空7予報、観測なしの提出、非最適予報、負の得点での完了を維持。
原作と異なる段階的省略・表示・全7予報の支援比較はlesson_meta.jsonとLESSON.mdに記載。
Python 3.12.14 / Pyxel 2.9.9 / Linux。SDL_AUDIODRIVER=dummy、-Bで実行。

モデル・入力
- 標準ライブラリunittest 44件が成功。qa/model_tests.txt。
  全5段階のデータ、カード重複、候補集合、ビット集合、採点、境界、期待点の分数、同点、文中の練習数値を検査。
  原作由来の336ケースを最終段階へ照合し、04の原版168ケースも照合。
  候補0は空の予報と同時でもデータ不整合例外。空の予報0は提出拒否。
  候補にない天気の予報も受理。全て予報の無観測3日=+3、曇だけの3日=-12でも完了。
  非干渉試験は未観測の真相、同じ観測値を持つ別カード、未開示の未来を差し替えて公開表示/比較表が等しいことを確認。
  押しっぱなしは全対象キー、同時押しは全対象キー組合せ、全解放までの拒否、説明/表紙の優先順位を検査。
  初回と練習、Undo/再開/比較版をまたぐ観測・開示の保持、練習のみ3日での完了、支援使用履歴を検査。
- 原作ソースの直接比較も成功。qa/canonical_comparison.jsonとqa/canonical_recheck.txt。
  336数値ケース（8真相×3観測状態×7予報×2版）。
  13入力トレース・480フレーム状態を比較。
  6文脈×91同時押しペア=546ケース、2,184フレームでゲート・状態・優先順位を比較。
  原作のState/Timeline/公開値と対象入力の処理結果が一致。教材固有の支援記録と見た目のnoticeは別管理。
  原作51ファイルのSHA256は前後一致。原作の読み込みにもPyxel importは不要。
- 固定fixture qa/canonical_reference.jsonは原作から直接生成。
  原作が隣にない配布フォルダーでもテスト可能。seedの秘密列はfixtureに列挙せずSHA256で照合。
  固定結果を含む検証用資料なので初見問題のヒントとして使わない。

実ランタイム
- 実Pyxel headlessの25チェックポイント、各12フレーム以上が成功。qa/render_runs.json。
  各PNG/JSON/logに初期画面5枚、重複参照、観測2種、二回目観測拒否、空予報、提出、期待点同点、支援結果、再演、比較版、説明、3日完了、練習のみ完了、再開を保存。
  Pyxelのupdate/drawを実行し、キー集合をController.feedへ押下/解放で合成。
  各JSONには実行ファイルのSHA256と公開snapshotを保存。秘密の未来カード列を記録しない。
- 5本を一つずつ日本語と空白を含むパスへコピーし、無関係の日本語/空白CWDから起動成功。qa/isolation_runs.json。
  プログラム側はその.pyだけ。相対PNGと明示UTF-8の相対JSONが生成された。
  PYTHONUTF8=0、PYTHONIOENCODING=cp932も設定して確認。
- 教材だけを別フォルダーにコピーし、-B -Sで44試験成功。原作もsite-packagesも不要。qa/standalone_tests.txt/json。
- 誤ったCLI 15ケースは全てexit 2、Pyxelをimportする前に拒否。qa/cli_invalid.json。

画像確認
25枚の実PNGを5枚のコンタクトシートで確認し、完成画面の単独PNGも確認。
公開候補の枠・除外表示、選択と未開示の区別、負の分数と同点、ANSWER KNOWN: REPLAY、PRACTICE RESULT、完了表示を確認。
比較表は右側パネルを覆う説明表示で、Tabで閉じると選択/結果が見える。比較中に答えを先取り表示しない。
qa/visual_review.json。コンタクトシート作成は既存のPillowを使用し、新規インストールなし。

権利と差分
原作LICENSE全文をLICENSEと5本の冒頭コメントにそのまま保持。
原作LICENSEが参照するNoto通知とPyxel通知を原文一致で収録。字形データは教材に含まない。
qa/rights_packaging.json。隣接4差分は実ファイルから生成し、試験でも完全一致を検査。

原作の証拠は別扱い
qa/original_evidenceは親タスクが事前に実施した原作19テストと実Pyxel自動デモの証拠のコピー。
原作のfresh-unit.log、fresh-render.logと4枚のPNG、SHA256/indexを保持。
原作の19試験を教材44件へ加算しない。原作デモも教材25チェックポイントへ加算しない。
原作の再演画面frame_0695.pngも参照して、答えを知った状態と未開示の文言を区別。

未検証
人間の試遊、OSキーボードイベント、Windows/macOS GUI、ブラウザ、音声。
headless自動操作とモデル試験の証拠であり、人の上達・面白さ・予測力・確率校正を示すものではない。
この教材フォルダーから公開操作は行っていない。

再現
python -B -S -m unittest -v test_stages.py
python -B tools/render_qa.py
python -B -S tools/verify_original.py "/原作へのパス/080_forecaster_desk"
python -B tools/check_freeze.py
render_qa.pyはQAファイルを再生成するので、再実行後のフリーズ差異は通常の更新として確認する。

フリーズ
qa/freeze_manifest.jsonは全配布ファイルのSHA256と明示した除外（manifest自身・確認ログ、__pycache__）。
qa/freeze_verification.txtは最終照合結果。変更後は試験を再実行して意図的にtools/freeze.pyで更新する。
