# distance_to_hardstop_yen Semantics Audit

Verified source formula:
- `GetPositionState` lines 9554-9607 builds `ps.floatingProfit` as the sum of `POSITION_PROFIT + POSITION_SWAP` for EA positions.
- It does not explicitly add commission.
- `GetFloatingLossYen` lines 2045-2050 returns `-ps.floatingProfit` when floating P/L is negative, otherwise 0.
- `GetHardStopThresholdYen` lines 2060-2073 selects fixed, initial-balance-R, or balance-percent threshold.
- For the current baseline, `HardStopBasis = HARDSTOP_BALANCE_PERCENT` and `HardStopFloatingLossPercent = 12.0`.
- `GetBalancePercentHardStopThresholdYen` lines 2052-2057 uses `AccountInfoDouble(ACCOUNT_BALANCE) * HardStopFloatingLossPercent / 100.0`.
- `IsHardStopTriggeredByBasis` lines 2076-2081 returns true when floating loss is >= threshold, or margin level is <= `HardStopMarginLevel`.
- `PostHedgeDiagDistanceToHardStop` lines 7294-7299 returns `threshold - GetFloatingLossYen(ps)`.

Meaning:
- Unit: account currency yen.
- Positive distance: floating-loss hardstop threshold has not been reached.
- Zero distance: floating-loss threshold is exactly reached.
- Negative distance: floating-loss threshold is exceeded.
- Floating P/L includes swap via source; commission is not explicitly included.
- Spread is included indirectly through MT5 current `POSITION_PROFIT`, which depends on current bid/ask valuation.
- Slippage is not included.
- Balance-percent threshold includes realized balance changes through `ACCOUNT_BALANCE`.
- 50k / 100k runs differ because the balance-percent threshold depends on the account balance.

Why distance=-8.16 with HardStopNow=false appeared:
- In source, `TraceRuntimeEvaluationStage` trusts the boolean `hardStop` argument passed to it.
- OnTick lines 2137-2163 call `TraceRuntimeEvaluationStage` for TICK_START / AFTER_FLOATING_PNL_UPDATE / BEFORE_HARDSTOP_EVALUATION with `hardStop=false`.
- OnTick line 2209 also passes `hardStop=false` for AFTER_MARKET_STATE_UPDATE.
- Therefore HardStopNow=false in those EVAL_STAGE_TRACE rows is not the same as recomputing `IsHardStopTriggeredByBasis` from the same `PositionState`.
- The distance field is computed from the real floating loss formula, while the diagnostic stage's HardStopNow field can be forced false by the stage call.
- Most likely root cause: diagnostic stage labeling created an artificial pre-HardStop state, not a formula mismatch in `GetFloatingLossYen`.

Design consequence:
- TA9 safe logic must not use stage-passed HardStopNow from old EVAL_STAGE_TRACE rows as source of truth.
- A shadow evaluator must create a single immutable snapshot and compute both `distance_to_hardstop_yen` and `HardStopNow` through the same shared function on the same `PositionState`.
- Any snapshot where `distance_to_hardstop_yen <= 0` and `HardStopNow=false` must be logged as `SNAPSHOT_PARITY_ERROR` before any future order-sending design is considered.
