Incident · 2026-04-13

The pullback evaluator misfired. Here's exactly what happened.

April 13, 2026 · two losses · -$57.50 + Undertow misfire · fixed same evening

What you would have seen on the day.

At ~9:51 ET the desk fired a SHORT alert on QQQ. Anyone watching the chart in real time would have seen the same thing we did: the price action did not support a short. QQQ had wicked once below the opening range and then rallied straight back through it. The tape was long. The alert said short.

The trade closed about ten minutes later on a hard stop, down about 43% on the contract. -$57.50 on the book.

What actually happened.

Three subtle bugs were stacked inside the pullback evaluator. Any one of them in isolation would probably have stayed harmless. All three together produced a trade going the wrong way.

  1. The pullback rule was firing on the breakout bar itself. A pullback signal is supposed to fire only after price has broken a level, returned into the range, and then started rolling over from inside. Instead the evaluator was matching the same bar that registered the original break. The bar that triggered the breakout trivially satisfied the “came back into the range” condition, because by definition the breakout bar straddles the level.
  2. The signal-context scorer was inverting failure signals. When a short setup has a fast reclaim back above the break, that is a failure. When the second-bar confirmation never lands, that is a failure. The scorer was counting both of those as +1 each instead of -1 each. Two failures were being read as two confirmations. The evaluator looked at an already-invalidated setup and saw a 4/4 score.
  3. There was no current-price sanity check before the trade fired. By the time the order went out, QQQ had moved several minutes further into long territory. The signal stored at first match was sent straight to the broker without checking that the current tape still supported that direction.

Net result: a SHORT PUT bought into a long-direction tape. -$57.50, -43.2% on the contract, closed on a hard stop.

The second loss.

Later that morning, a second module on the desk — the Undertow flip detector — fired a LONG entry near the day's high. Undertow is supposed to catch reversals, but the trigger it was using required a confirmed 10-bar trend with successive higher lows and a clean VWAP break. By construction, that signal can only fire after a move has already extended. On a day where the first trade had been classified the wrong direction off a wick, the flip went the wrong direction too. We bought the high.

Two trades in one session, both on the wrong side of the real intraday move. The first one was caused by the bug stack above. The second was caused by a structural property of the Undertow trigger: it cannot fire in time on this kind of day.

What was fixed.

That same evening, three changes shipped in commit ca22b57.

  1. The pullback evaluator now walks historical bars only to track state. The pullback fire is evaluated only on the most recent bar. And before any pullback is eligible, price has to have actually re-entered the range from outside. Stale signals cannot be generated.
  2. The signal-context scorer was inverted. A fast reclaim or a missing confirmation is now a hard veto: score zero, log the veto reason, do not arm. The remaining two components are the only inputs to the score.
  3. Before any trade fires, the evaluator now pulls fresh one-minute bars and runs two checks: a structural check that the current close is on the correct side of the range for the trade direction, and a drift check that price has not already pushed 30% of the range width past the pullback zone. If either fails, the trade is killed.

Undertow was redesigned in a follow-up. The new version runs a continuous 1.5R “exhaustion ceiling”: if a move has already extended past the point where a flip would still make sense, the detector cannot fire. The structural lateness that caused the second loss is gone.

What we learned.

Three bugs in the same code path is not a coincidence. It is a sign that the test coverage on the pullback evaluator was too thin — thin enough that an inverted score, a stale-bar match, and a missing sanity check could all live there at the same time without anyone noticing. We have added more in-process invariants on the path, and we now run paper-mode replays of any meaningful change to the evaluator before it touches the live book.

We also added a one-shot direction lockout per day: once the desk has taken a position in a direction on a symbol, it cannot flip and re-enter the opposite side later in the same session. That is a hard guardrail, not a heuristic. And the scanner watchdog that boots before the open and self-heals if the launch agent unloads is now public — if the desk goes quiet, it should be loud about it.

Why we’re publishing this.

A track record without losses isn’t credible. A track record that hides the embarrassing days is worse than no track record. We log every loss in public — including the ones caused by our own bugs.