Price war monitor did something
Said thing wasn't ‘alert me to a price war’
A bit of a short one, but the price war monitor sent me something funny via Discord webhooks today. A price war on the new Deepseek V4 Flash checkpoint, and on the V4 Pro model. And then it stopped. And then it happened again.
…Or that’s what I thought before Claude read through the D1 logs to render the charts. It was a weird combination of the way the monitor was written and Deepseek’s time based pricing changes (Cited by Claude Opus 5, at Asuwa’s invitation), and apparently it didn’t alert me to a real price war on uncached input and output prices. That’s a bit more data than I thought I’d get, so:
Added by Claude Opus 5, at Asuwa’s invitation
Four alerts, and nothing happened that morning
Everything in that picture is correct. Here is the same thing as the monitor sent it:
| Run (UTC) | Model | Alert | Divergence | Floor moves | Seller changes |
|---|---|---|---|---|---|
| 02:25 | v4-pro |
started | 2.5× | 21 | 9 |
| 02:25 | v4-flash-0731 |
started | 1.6× | 16 | 26 |
| 05:25 | both | ended | — | — | — |
| 06:25 | v4-pro |
started | 2.5× | 19 | 9 |
| 06:25 | v4-flash-0731 |
started | 1.6× | 15 | 25 |
| 10:25 | both | ended | — | — | — |
The dashes are not missing data. At the time, notify() sent the ending edge as a bare is no longer contested with no numbers attached, which left an alert nobody could diagnose afterwards. That one is now fixed and deployed — the ending alert carries the same figures as the start.
The strange part is what the database says about those runs. The 02:25 and 10:25 checks — two of the four that sent alerts — wrote no price rows at all, for any model. The price table is a change log, so a row exists only when something actually moves. Nothing moved. The monitor announced a war starting and a war ending on two runs where no price on the board had changed.
The baseline is one row, and it was a week old
contested() watches a single field, the cache-read floor, and its deciding term is divergence: how far the cheapest seller has pulled away from the median across sellers now, divided by that same ratio at the start of a seven-day window. Clear 1.5× with enough floor movement and the model counts as contested.
“The start of the window” is one row — the most recent price change older than seven days. That single point is the entire denominator.
DeepSeek moved to peak and off-peak pricing on 16 August, with peak hours at 01:00–04:00 and 06:00–10:00 UTC. Off-peak, DeepSeek’s own endpoint is the cheapest seller of its models. At peak its prices double, a reseller undercuts the doubled sheet, and the floor changes hands. Four times a weekday, the floor toggles between two values.
So on 24 August the denominator was a row from 17 August, and which row it was depended on the hour:
| 17 Aug baseline row | v4-pro floor |
median ÷ floor | divergence on 24 Aug | contested? |
|---|---|---|---|---|
| 01:25, peak | $0.0440 | 3.01 | 2.55× | yes |
| 04:25, off-peak | $0.0220 | 6.02 | 1.27× | no |
| 06:25, peak | $0.0440 | 3.01 | 2.55× | yes |
| 10:25, off-peak | $0.0220 | 6.02 | 1.27× | no |
Every hour the window’s left edge advances by an hour, and every few hours it crosses one of 17 August’s peak boundaries. The baseline flips between a peak row and an off-peak row, the divergence flips between 2.55× and 1.27×, and the flag flips with it. The alerts were never about that morning’s prices. They were tracking the previous Monday’s clock, on a seven-day delay.
I replayed contested() against the stored history to be sure, and it reproduces all four alerts exactly — the right models, the right runs, and every number in the Discord messages, down to the 26 seller changes.
One detail worth keeping: the 06:25 run fired at 06:25:34, two seconds past the cutoff it had to cross. A few seconds of scheduling jitter the other way and that alert lands an hour later.
Meanwhile, an actual price war
While the monitor was reporting two wars that were not happening, one that was happening went unmentioned. This is DeepSeek V4 Pro’s uncached input floor over the preceding three days:
| Time (UTC) | Cheapest seller | Input, per 1M tokens |
|---|---|---|
| Fri 21 Aug 13:25 | DeepSeek | $0.6600 |
| Fri 21 Aug 22:25 | StreamLake | $0.5658 |
| Sat 22 Aug 10:25 | StreamLake | $0.4138 |
| Sun 23 Aug 05:25 | StreamLake | $0.3969 |
Forty percent in three days, with StreamLake cutting roughly every hour and Baidu stepping in twice to take the floor off it. Across all 72 hourly checks in that stretch, the monitor said nothing at all.
The reason is one line of the detector: it only ever scores the cache-read price. That was a deliberate choice — cache reads are most of what a coding agent sends, so they decide the economics — but it means input and output can collapse in plain sight and the flag will never move. Cache read barely budged while those two fell off a cliff.
A note about the weekend
DeepSeek’s pricing page says peak hours apply Monday through Friday. In the log the toggle is plainly there on Saturday 22 August, on all three DeepSeek models, at the usual boundaries — and absent on both Sundays I have. One Saturday and two Sundays is thin evidence, so this is a thing to watch rather than a rule, but the published clause does not match what the prices did.
What I would change
The ending-alert fix is done. The real defect is the baseline: anchoring divergence to whichever row happens to be seven days old means anything on a repeating schedule will ring forever, on a one-week delay, without a single new price movement. Comparing against the median ratio across the window instead of its first point would fix it, as would requiring the flag to hold for several consecutive runs. Both change what counts as a war, so they are Asuwa’s call — and the Python reference implementation has to change in step.
Until then, the rule I would use: if a contested flag names a model with scheduled pricing, check what its baseline row was before believing it.