History was only fetched by the startup seed, so a Schwab outage stayed a
hole until the next deploy — Sept 9 to 24 after a refresh token expired.
A reconnect more than two minutes past the last bar now fetches the gap
from Yahoo, fills empty buckets only, refolds the live forming buckets,
rebuilds levels without alerting, and resyncs every socket.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Two faults, both introduced by the tick feed, both visible as a huge bar that
flattened the price scale.
A LEVEL_ONE_FUTURES update arrived carrying LAST_PRICE: 0. The parser rejected
None, but 0 is not None, so a minute opened at zero — o=0.0 h=7777.25 l=0.0 —
and provisional_higher carried that low into 5m, 15m, 30m, 1h and the daily bar.
Non-positive prices are treated as absent now, so the last real price carries
forward and the update still counts as the trade it is.
Separately, store.put replaced a bar only when it matched the tail. That was
sufficient while one closed bar arrived per minute, but ticks open the next
minute before CHART_FUTURES delivers the previous one, so the exchange's own bar
stopped matching the tail and was silently dropped — leaving the tick-built
approximation, with its partial volume, in place permanently. put now searches
back a bounded number of buckets for the one it belongs to, and refuses to let a
provisional bar overwrite a settled one.
Tests cover all three invariants: a zero price parses as a trade with no price,
a late closed bar replaces its bucket and keeps the exchange's volume, and a
tick cannot overwrite a settled bar.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
It was never in the enabled timeframes, so it held zero bars and produced no
levels, but it still carried weight 8 in the scoring table and forced
bucket_start to special-case a wall-clock ET anchor whose entire purpose was
surviving DST transitions. That was the most intricate logic in session.py,
maintained for a timeframe nobody used.
Daily is now the only session-anchored bucket, which is a much easier rule to
state and to keep correct. The DST parametrised tests go with it; the Sunday
open and daily boundary cases remain.
Manual-line tests move to 1h, so the weight assertions drop from 8 to 4.
The plan document keeps its 4h examples — rewriting a dozen illustrative
sentences would churn more than it clarifies — but the timeframe-roles section
now records the removal so nothing reads as a spec to build.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>