TASK: H-1 — feed the traded bar to the position monitor so the ratified
      stop-fill model runs in PRODUCTION, not only in replay. Pure wiring
      of an already-written, already-ratified policy path. No new logic.

## Established context (verified in code 2026-09-06)

- api/v2_scheduler.py:252 builds PositionContext with ltp_by_id,
  spot_by_sym, diagnostics_by_id — and NO bar_by_id. It defaults to {}
  (context.py:117), so snapshot.current_bar (context.py:164) is None on
  every production tick.
- hard_stop_loss_v2.py:233 therefore takes its `if bar is None` branch and
  publishes execution_price=None; _fill_price then books the ~15s tick
  mark instead of the stop level.
- bar_by_id is populated in exactly ONE place: shadow_mode/
  replay_signals.py:461 (TradedBar(...)). The 2026-08-15 stop-execution
  amendment — "difference now 0.00" — has only ever been exercised by
  replay. It has never run in a live paper trade.
- Measured cost (weekly analysis): ₹538.36 of slippage across 17 stop
  exits; P15's promoted stop 110.364 filled at 109.10, turning a winner
  into −₹35.75. The counterfactual grid shows this is the ONE change that
  moves outcomes from negative to positive.

## OBJECTIVE

Populate bar_by_id in the production PositionContext with the SAME TradedBar
shape replay already constructs, so hard_stop_loss_v2 (and any bar-aware
policy) takes its ratified branch in production. Zero change to policy
logic, thresholds, or the TradedBar contract.

## Verify the premises

1. The exact TradedBar type replay builds (shadow_mode/replay_signals.py
   ~461) — fields, units, and where each comes from. The production bar
   must be byte-identical in shape and meaning (OHLC of the option
   contract's just-closed 1m bar, or whatever replay actually passes —
   confirm it is the OPTION's bar, not the index's; if replay passes the
   underlying's bar the whole fix changes and you STOP and report).
2. Whether the production tick already HAS the bar in hand. The scanner
   fetches option candles; find whether the just-closed bar for each open
   position's contract is available at scheduler tick time WITHOUT a new
   broker call. If it requires a fetch, price that fetch against the rate
   limit (0.09 req/s observed vs 3 req/s cap — cheap, but confirm) and
   report the added call count.
3. hard_stop_loss_v2's non-None branch (lines ~233-274): what `basis` and
   `fill` it computes, and that a correctly-supplied bar makes execution
   deterministic. Confirm the fill is CLAMPED to the bar's own range
   (a stop can't fill beyond the low/high actually traded) — if the
   ratified model does not clamp, report it; do not add clamping as a
   silent extra.
4. Every OTHER policy that reads current_bar (grep): supplying the bar
   must not silently change any policy that was relying on None. List them
   and their behaviour before vs after a non-None bar.

## Do NOT change

hard_stop_loss_v2's logic, thresholds, or fill arithmetic · the TradedBar
type · trailing/break_even/spike/target policies' logic · the tick cadence ·
spot handling (H-5 is a separate task; do not fold it in) · the stop model ·
any config key. This task ADDS one already-declared field to one context
construction. If it grows past that, STOP.

## Implementation

1. At v2_scheduler.py:252, build bar_by_id for the open positions from the
   bar source premise 2 identified, as the SAME TradedBar replay builds,
   and pass it into PositionContext.
2. If a bar is genuinely unavailable for a position on a given tick (blind
   minute / rate-limited), that position's entry is None (the map tolerates
   Optional per context.py:117) — the policy then takes its existing
   None branch for THAT tick only, exactly as today. Missing data must not
   fabricate a bar.
3. Nothing else.

## Tests

- Unit: PositionContext at the scheduler now carries bar_by_id; a fixture
  open position with a known just-closed bar makes hard_stop_loss_v2 take
  its non-None branch and fill at the ratified level, not the tick mark.
- The None-bar tick still books the tick mark (no regression for blind
  minutes).
- Parity: the production fill for a fixture now equals what replay computes
  for the same bar — the "difference now 0.00" property, in production.
- Premise-4 policies: unchanged behaviour proven on fixtures.
Then the FULL suite:

    bash backend/scripts/ci/run_all.sh

All 13 gates green.

## Verification report

A. Files changed  B. Premise-1 TradedBar shape (and confirmation it is the
OPTION's bar)  C. Premise-2 bar availability (existing data vs new fetch,
with added call count)  D. The parity proof (production == replay fill on a
fixture)  E. Premise-4 other-reader inventory  F. Clamp-to-bar-range
verdict  G. 13 gates  H. Premises that did not match  I. Unknowns

CRITICAL: This makes a ratified, tested, replay-proven policy actually run
in production. If premise 1 finds replay passes the INDEX bar (not the
option's), or premise 2 finds the bar needs a broker fetch that the rate
limit cannot afford, STOP and report — either finding changes the design
and is Nitin's call.
