EQ_S_TIMING_CLARIFICATION r02（P28-02-EQ repair 1。r01 の全文を保ち、T4 だけを製品の source に合わせて置き換えた版。base 2549cf7d6992560b850bbd11934e3c14b39a1988。SPEC、TASK_INSTRUCTIONS、eq/references、eq/registration、ACCEPTANCE の6条件は変更しない。EQ1 の「比べない欄は理由と実際の値を記録する」の範囲で、S 層の中の実時間の値の扱いを確定する。新しい数値、製品の仕様、原本の 30/88、課金、権限は変更しない）

事実（worker の blocked の返答 eed3a23a…、Root の照合）
- 保存と読込の完了は、_complete_save_operation（autoload/simulation_runtime.gd:4734）→ _publish_actor_event で、domain event を1件発行する。その payload は _save_event_payload（:4745）で、実時間の duration_us と runtime_duration_us の2つの key を、必ず含む。
- この event は systems.runtime.domain_events.recent_events に入るので、create_snapshot()（:539）の S 層の中に、実時間の値が保存される。そのため、E4 の load の直後の S の完全一致と、同じ版の2 PID の差0は、そのままでは成立しない。SPEC §3.2 の実時間の除外は K 層の _samples と _totals だけで、S 層は対象にしていなかった。

規則（RESTART の受入済みの方式と同じ。restart_probe.gd の E の置き換えと記録、redact_payload の2 path の対応、CLARIFICATION_01 C2/C3 の X(B, ev)）

T1 閉じた対象
- 対象は、event 要素の source_service が "save_service" で、event_type が _complete_save_operation の出す9種のいずれかである場合の、payload の key duration_us と runtime_duration_us の2つだけ。9種は SAVE_CHECKPOINT_SUCCEEDED、SAVE_CHECKPOINT_FAILED、SAVE_LOADED、SAVE_LOAD_FAILED、SAVE_MIGRATION_SUCCEEDED、SAVE_MIGRATION_FAILED、SAVE_RECOVERY_LOADED、SAVE_RECOVERY_CANDIDATE_LOADED、SAVE_RECOVERY_FAILED。
- 場所: S 層、latest_snapshot、E2 の全イベントの記録の中の、該当する event 要素の payload。
- それ以外の場所で、実時間と思われる値が S にあった場合は、黙って扱わずに失敗として記録し、判断に戻す（新しい事実として扱う）。

T2 比較のための正規化（可逆。値は捨てない）
- 比較する状態の deep copy を作り、T1 の各 key の値を、typed の marker {"redacted_timing": "<key>", "typeof": <元の値の typeof>} に置き換える。元の値は、sidecar に、path（その要素の event_id と key を含む）・typeof・値として、全て記録する。元の状態は変更しない。
- 要求:
  - (1) 置き換えた path の集合が、比べる両側で完全に一致すること（event_id で対応させる）。
  - (2) 正規化した状態の var_to_bytes が、両側で完全一致すること。一致しない場合は、RESTART の修正8の typed の正規表現で path を特定し、dict の列挙の順序だけの差を記録する。それ以外は不一致。
  - (3) 同じ PID の中で、正規化した状態に sidecar の値を戻すと、元の状態の var_to_bytes と完全一致すること（可逆であることの証明）。
  - (4) 元の値の typeof が int で、0 以上であること。それ以外は失敗。
- 時間の値そのものは、版の間でも、PID の間でも比べない（実時間に依存するため）。理由と、各側の実際の値を記録する。

T3 latest_digest
- 同じ PID の中で、製品の latest_digest が、SimulationDigest.compute(latest_snapshot) と一致することを確かめる（製品の digest の自己整合）。
- PID の間と版の間では、latest_snapshot が T1 の値を含む場合、製品の latest_digest の文字列は比べない（実時間を含むため）。代わりに、T2 で正規化した latest_snapshot に対して harness が計算した値を、「harness の正規化 digest」と明記して比べる。T1 の値を含まない場合は、製品の latest_digest を文字列の完全一致で比べる。どちらで比べたかを記録する。

T4 E2 と E4 の IO event（製品の source に合わせて、操作ごとに分ける）
- E2 の全イベントの比較にも T2 を適用する。event_id・event_type・absolute_minute・source_service・entity_ids・causation_command_id と、T1 以外の payload の欄は、完全一致を要求する。開始の counter の一致の要求は、従来どおり。
- 操作ごとに、実際に増えた domain event の件数と、その全ての内容を記録して検査する。監査のイベントを無視しない。
  - 直接の restore_snapshot(P)（autoload/simulation_runtime.gd:587 → _restore_snapshot_internal（:591-1476））: この経路には _complete_save_operation も _publish_actor_event も無く、最後は _publish_snapshot → true で終わる。
    - 成功の場合: 直後の S 層が、P を規則どおりに復元したものと、T2 の正規化の後で完全一致すること。SAVE_* の IO event は0件であること（1件以上あれば失敗）。
    - 失敗の場合: 戻り値が false で、S/K/C 層と全イベントが不変であること（追加の event は0件）。
  - load_from_path の成功（:4223 → _finish_load_operation → _complete_save_operation(…, SAVE_LOADED)）: 直後の状態が、CLARIFICATION_01 C3 の X(P, ev_load) と、T2 の正規化の後で完全一致すること。SAVE_LOADED の IO event がちょうど1件であること。
  - load_from_path の失敗（同じ経路の SAVE_LOAD_FAILED）: 直後の状態が、CLARIFICATION_01 C2 の X(B, ev_fail) と、T2 の正規化の後で完全一致すること。SAVE_LOAD_FAILED の IO event がちょうど1件であること。
  - X の規則は従来どおり: counter+1、published_ids への sort 挿入、recent の上限256での先頭の落とし方。それ以外の差は不一致。
- 各操作の実際の件数（0 か 1）を、期待の件数と並べて記録する。期待と違えば失敗にする。

T5 試験（test_eq.py）
- 正常試験: T1 の対象の正規化と、可逆性の確認。
- 拒否試験:
  - 直接の restore_snapshot に SAVE_* の event を要求する、または期待の件数（直接の restore は0、load は1）と違う実際の件数を合格にする
  - T1 の外の key や event の置き換え
  - 9種の外の event_type、source_service が違う場合
  - 片方の key だけの置き換え
  - path の集合の不一致
  - sidecar の欠落や改ざん（元に戻らない）
  - 時間の値の、PID の間・版の間での一致の要求
  - 実時間を含む latest_digest の文字列の比較
  - 置き換えた値を統計や判定に使うこと

worker への手順
- 前回は実装0なので、SPEC・TASK・この補足に従い、eq/** に SPEC §2 の6ファイルを実装する。SPEC・TASK・eq/registration・eq/references は変更しない。
- engine を使わない test_eq.py の全件 PASS を局所で確かめ、生出力を報告し、正式な JSON で提出する。
- engine の起動、git への書込み、製品の変更、全回帰はしない。通常の実装上の選択は、記録して進める。
