# Same-Tick Immutable Snapshot Contract

Objective:
TA9, current close eligibility, and HardStop must not reference different values inside one tick/eval cycle.

Contract:
- One basket / one eval cycle / one immutable ClosePriority snapshot.
- All close candidates read that snapshot; none recompute basket P/L during arbitration.
- Candidate selection snapshot and order-send result are separate records.
- Retry on the next tick receives a new snapshot id.
- The snapshot is append-only for logging; order results attach to it by id.

Required fields:
- priority_snapshot_id
- basket_uid
- server_time
- server_time_msc when available
- tick_sequence_id
- eval_cycle_sequence
- eval_stage_index
- basket lifecycle state
- hedge state
- bid
- ask
- spread
- basket floating P/L
- commission if available; otherwise explicit null/not_collected
- swap
- current basket net P/L
- hardstop threshold
- distance_to_hardstop_yen_raw
- distance_to_hardstop_yen_normalized
- HardStopNow
- HTE state
- HTE currently eligible
- Recovery currently eligible
- BasketClose currently eligible
- ClosePriorityOK
- ClosePriorityBlocked
- pending close state
- market/session state
- TA9 raw condition
- TA9 safety condition
- selected close reason
- suppression reason

Source of truth rules:
- `HardStopNow` and `distance_to_hardstop_yen` must come from the same helper and same PositionState.
- Diagnostic stage traces that pass hardStop=false are not source-of-truth HardStop snapshots.
- Current HTE/Recovery/BasketClose eligibility must be evaluated from current snapshot fields only.
- Future HTE timing, final close reason, actual HardStop time, and future max/min P/L are forbidden from candidate selection.

Error handling:
- If distance <= 0 and HardStopNow=false, emit SNAPSHOT_PARITY_ERROR.
- If HardStopNow=true and TA9 raw/safe is true, emit TA9_SUPPRESSED with reason HARDSTOP_NOW_TRUE.
- If pending close state is not NONE, suppress TA9 and log the pending reason.
