EQ_STAGED_IMPLEMENTATION_PLAN（P28-02-EQ repair 3 以降。base 2549cf7d6992560b850bbd11934e3c14b39a1988。SPEC、TASK、6条件、eq/references、eq/registration、EQ_S_TIMING_CLARIFICATION r01/r02、EQ_ENVIRONMENT_FIELDS_CLARIFICATION r03 は全てそのまま有効。変えるのは、工程と、成果物の内部の設計の固定だけ）

前回までの事実
- repair 2（run 84ca0ff8…）は、IMPLEMENTATION.md と compare_versions.py などを作った後、item_30 で全てを削除し、「6ファイルと unit の PASS を提供できない」として、自分から終了した。仕様の不足の指摘ではない。packet は 94 KB あった。
- この失敗は失敗のまま保持する。削除したことを成功として扱わない。

工程の変更（必須）
- G1: **作ったファイルは、削除しない**。完成していなくても、W の eq/ に残す。各 run の最後に、eq/PROGRESS.md に、終わった段階・残りの作業・現在の試験の結果を書く。
- G2: 1回の run では、下の**1つの段階だけ**を行う。始める前に eq/PROGRESS.md を読み、次の段階から再開する。前の段階のコードは作り直さない。
- G3: 各段階の終わりに、engine を使わない python3 test_eq.py を実行する。その時点で存在する試験が、全件 PASS になるまで直す。生出力を eq/UNIT_OUTPUT.txt に保存する。
- G4: 段階1〜3の終わりには、正式な JSON の status を blocked にし、findings に「段階 Sx 完了（失敗ではない。次は Sx+1）」と PROGRESS.md の要点を書いて返す。段階4の終わりにだけ、提出する（status を submitted 相当の正式な提出にする）。
- G5: 通常の実装上の判断（関数の分け方、名前、試験データ、記録の書式）は、IMPLEMENTATION.md に記録して進める。blocked にしてよいのは、原本の仕様・値・権限・課金・受入に影響する未確定事項がある場合だけ。
- G6: engine の起動、git への書込み、製品の変更、全回帰はしない。SPEC、TASK、eq/references、eq/registration は変更しない。

固定するインターフェース（6ファイル。SPEC §2）

1. compare_versions.py（Python のみ。engine を使わない）
   - normalize_events(events, profile_root) -> (normalized, sidecar):
     - r03 の F1〜F3 を、JSON の event の一覧に適用する。
     - 閉じた一覧の外の *_us / *_ms / profile_root を含む文字列は、正規化せず、violations として返す。
   - restore_events(normalized, sidecar, profile_root) -> events: 逆の復元（完全一致の確認に使う）。
   - compare_reports(a, b) -> dict: 2つの report（同じ版の別 PID、または前後の版）を比べる。
     - 毎分の checkpoint の S_norm_sha と latest_norm_sha の一致
     - digest の規則（r02 の T3）
     - K と C の、SPEC §3.2 に列挙した欄
     - E2 の正規化した全イベント（開始の counter の一致が前提）
     - E3/E4/E5 の scenario の結果の一致
     - 比べない欄は、理由と両側の値を記録する
     - 差は path ごとに返す
   - check_source_closure(before_map, after_map, allowed_changed) -> dict: SPEC §2 と OPT r02 §2。追加・欠落・登録されていない差分を拒否する。
2. eq_probe.gd（GDScript）:
   - 起動の6段階は、DIAG の diag_probe.gd の構成をそのまま参考にする。
   - 役割は R と O（env の THE_TREE_EQ_ROLE）。
   - 観測の checkpoint は B1 と、30分の各 tick の最後（31個）。各 checkpoint に、次のものを置く:
     - minute
     - S_raw_sha、S_norm_sha（GDScript の中で F1〜F3 の typed の marker を使って正規化した後の var_to_bytes の SHA）
     - 正規化した S の path の hash の表（depth ≤ 4）
     - latest_norm_sha
     - digest の情報
     - K と C の全体
     - sidecar
   - E2 は subscribe('*') で、全イベントの JSON（正規化の前）を記録する。正規化は compare_versions.py で行う（GDScript と Python で、同じ規則の二重実装をしない）。
   - E3/E4/E5 の scenario は、SPEC §3.3 の専用の区間で行う。各区間について、開始と終了、操作、code、前後の S/K/C、件数（r02 の T4）を記録する。
   - stdout には、P28_02_EQ_REPORT=<json> をちょうど1行出す。終了は close_requested.emit()。
3. check_eq.py: report 1つを検査する。
   - 形式、必須の欄、矛盾
   - 閉じた一覧の外の差
   - probe の静的な禁止（autoload の class_name の参照、状態を変える呼出しの区間の外での使用、Variant からの := の推論）
   - SimulationDigest だけでの判定
4. run_eq.py: Root が実行する driver。
   - diag_p28_02.py の構成をそのまま参考にする（--check / --run、依存の SHA、1407 の source、凍結した S の照合、owned phase、guard、private profile、cleanup）。
   - phase は import、parse-base、parse-wrapper、R-A、R-B、O-A、O-B。
   - 成功したら、execution.json と bundle.json を作る。
5. verify_eq.py: --project-root . で、$BUILD_OUTPUT_DIR/p28-02-eq-evidence の bundle を結合する。bundle が無ければ失敗する。
   - 各 report に check_eq を行う。
   - R-A と R-B、O-A と O-B に compare_reports を行い、差が0であること（harness の正しさ）。
   - E3/E5 の、前の版での製品の失敗は、「既存の不具合」の一覧として出力する。harness の不合格とは区別する。
   - SPEC、TASK、eq/references、eq/registration の SHA を固定して照合する。
6. test_eq.py: 合成した入力だけで動く。各段階で、その段階の試験を足していく。

段階（1回の run で1つ）
- S1: compare_versions.py の全体と、その試験（F1〜F3 の正常と拒否、可逆性、比較、source の閉包）。PROGRESS.md と IMPLEMENTATION.md を作る。
- S2: eq_probe.gd の、起動・観測の checkpoint・E2 の記録・報告。check_eq.py の静的な検査と形式の検査、それぞれの試験。
- S3: eq_probe.gd の E3/E4/E5 の scenario、check_eq.py のそれに対する検査、試験。
- S4: run_eq.py と verify_eq.py、bundle の試験。全件 PASS を確かめて、正式に提出する。

Root への依頼（packet を小さくするため）
- actual_commander_context の key には、この計画の全文と RUN の判断だけを入れる。r01・r02・r03 の全文は、build/ に読取専用で置き、その path と SHA だけを渡す。eq/references は W の中にあるので、path だけで足りる。
