Mechanical R must respect the plan's own horizon

Found 2026-09-03 Status fixed (src/session.ts, horizonFor() in src/ledger.ts)

What we saw

Ride 137, GPRO, scored before the fix:

issued   entry $1.64  stop $1.4611  target $1.8686   (target = +1.28R)
MECHANICAL   first door = TARGET @ 2026-09-02T20:31:08Z   +1.28 R
REALISED     exit $1.65 @ 19:55:16Z                        +0.06 R
DELTA                                                      -1.22 R

20:31Z is 16:31 ET — thirty-one minutes after the close. And the lane's own thesis ends with 15:55 ET eject — SAME SESSION ONLY. The scorer charged a trader 1.22R for failing to hold through a door that opened half an hour after they were required to be flat.

Three independent pieces of evidence pointed the same way:

  1. GPRO's after-hours target, above.

  2. LHAI's daily bar opens at $0.83 — a pre-market print at 12:00Z. The regular session opened at $1.22. Databento's bars and ticks both span extended hours, so nothing may assume first-print-of-day is the open.

  3. The desk has already been burned by this exact thing. From a data-correction event on position 3:

    "Phantom stop-breach rescinded: poisoned quote rows (lone AH bid 2.80 stored as price; true last trade 3.25, day low 3.20 never touched stop 2.81); poller+query fixed in 78ba46b"

    One after-hours print triggered a stop that never happened.

Why it matters

A door touched outside the window a plan could act in is not a door. Counting it converts the mechanical leg from a measurement into an artifact, and since delta is realised − mechanical, every error goes straight onto a person's record.

What we did

src/session.ts resolves regular hours (09:30–16:00 ET) per date through the IANA zone, never a hardcoded offset — a four-year backfill crosses eight DST transitions and either constant is wrong for half the year. Tested on both sides of both 2026 transitions, and on the 15:55 ET eject, which correctly resolves to 19:55Z in summer and 20:55Z in winter.

horizonFor() derives the bound from the plan's own words — an eject time, SAME SESSION ONLY, never an overnight — plus time_stop_date. Tightest constraint wins. The walk, MFE/MAE and run-on are all bounded by it.

GPRO after:

MECHANICAL   neither door touched inside the horizon (same-session-eject)  +0.22 R
REALISED                                                                   +0.06 R
DELTA                                                                      -0.17 R
note: 9,308 of 22,410 prints dropped as outside regular hours

A 1.05R false accusation, removed. 42% of that ride's tape was extended hours.

The correction runs both ways

Worth recording, because it is the reason to trust the result rather than just prefer it. PCG 124 moved ~1R in the opposite direction: its stop had been "hit" after hours, which flattered the trader by making a −0.52R exit look better than the plan's −1.00R. With the horizon applied the plan would not have stopped out during the session at all, so the early exit reads as a cost.

Desk-level totals over 2026-09-01..02 barely moved:

                          before     after
selection  (the setups)   -1.49 R   -1.37 R
management (the people)   -1.71 R   -1.83 R
realised                  -3.21 R   -3.21 R   ← unchanged, as it must be

Individual rides moved up to 1R in both directions and the headline conclusion — management costs more than selection — survived unchanged. The finding did not depend on the bug.

Still open