Where session 7 sits
Session 6 ended with a playbook: say the ask, say the price, two minutes of urgency and stop, show the product, answer the room. Each line has a within-stream number. None of them says when. A CTA at minute 43 of a stream that is already converting is a CTA wasted; the same CTA at minute 43 of a stream that has been quietly sliding for three minutes is the one that pays. Tonight builds the thing that can tell those two minute-43s apart while they are happening, and session 8 puts it on the replay bench to find out what it was worth.
★ What you walk out with tonight. A nowcaster for the next five minutes of orders that beats "next five equals last five" over 6,720 backtest windows: MAE 9.41 orders per window at alpha 0.1 against 11.97 for the naive rule. An alert rule with two conditions, orders under 70 percent of the nowcast for three minutes and no CTA in the last six, and the base-rate table that says how often it fires on a host's own plan. And a replay loop that prints the producer's line minute by minute for one real stream.
LiveWhy five minutes3 min▶
The horizon is chosen by the people, not the model. A host can act on a cue within a minute: pick up the serum, say the price, ask for the order. A cue takes about two minutes to land in the ledger, because the viewer who hears it has to tap the card, read the page and pay, and session 2 found the stream itself carries a delay before the words even arrive. So one minute is too short to see anything change, and two is the earliest a change shows. Five is the shortest horizon a producer can plan against: long enough that a cue given now is fully inside it, short enough that the room at the end of it is still recognisably the room at the start.
Go longer and the forecast gets easier to hit and useless to act on. A thirty-minute forecast is mostly the room's slow drift, which the producer can see with her own eyes. The five-minute number is the one she cannot see: whether the next five will be better or worse than the last five, and by roughly how much.
Lumen Glow's first producer dashboard showed the running GMV total and a line for the room. The producer's own words on it: "It tells me what already happened. I need to know if I should interrupt her." The nowcast replaced the running total with one line, orders expected in the next five minutes against orders in the last five, and an amber state when the second was falling short of the first. She stopped watching the room curve within a week.
Self-studyThe vocabulary tonight leans on4 min▶
- Nowcast - a forecast of the immediate future from the immediate past, made while the thing is still happening. Distinguished from a forecast by the horizon (minutes, not weeks) and by the fact that the same model runs again every minute with one more row.
- Horizon - how far ahead the number reaches. Five minutes here. The backtest scores the sum over the horizon, not each minute inside it.
- EWMA - exponentially weighted moving average.
rate = alpha * new + (1 - alpha) * rate. Small alpha means long memory; the newest minute barely moves the estimate. Large alpha means the estimate chases the newest minute. - Backtest window - one (stream, minute t) pair at which the nowcaster is run using only rows before t and scored against rows t to t+4. Every window is a fresh forecast; 6,720 of them tonight.
- MAE - mean absolute error, in the unit of the thing forecast. Orders per five-minute window here. It is the average size of the miss, in either direction.
- Base rate - how often a rule fires when nothing is done about it, and how often a firing is followed by the thing it was supposed to predict. An alert without one cannot be judged.
- Alert - a rule that turns the nowcast into a yes or no. It is the only part of tonight a producer ever sees, so it carries the most design.
A small honest model
9 min liveThe nowcaster is two estimates and a loop. An order rate per viewer, smoothed so one noisy minute does not swing it, and a room projection, the last five minutes' slope carried forward but damped so it cannot run away. Multiply, sum five times, and you have a number. The diagram is the whole model and the whole backtest on one canvas, because a model this small should fit.
LiveThe arithmetic, and why the room matters more than the rate3 min▶
Orders in a minute are the room times the rate at which that room is ordering. Both move, but not equally. Across a five-minute window the per-viewer order rate of a given host in a given stream is nearly a constant with noise on it: one minute has three orders from a room of 800, the next has nine, the one after has four. Smoothing it is the right treatment. The room is different. It rises when the feed sends a burst of arrivals and falls when a segment goes stale, and those moves are real and they persist for minutes. A projection of the room is the right treatment for that.
So the nowcaster smooths the thing that is mostly noise and projects the thing that is mostly signal. The rate is an EWMA of orders[t-1] / room[t-1]. The room projection takes the change over the last five minutes, divides by five for a per-minute slope, and carries it forward five steps with a damping of 0.6 at each step, so a slope of plus twenty viewers a minute contributes twelve to the first projected minute and never compounds into a room that doubles. Each projected minute's room times the smoothed rate is that minute's expected orders; the five of them add up to the nowcast.
That is all of it. There is no seasonality, no exogenous regressor, no state vector. A model a producer can hold in her head is a model she will believe when it disagrees with her, and the backtest is what earns it the right to.
LiveThe backtest, and the bar that makes it mean something3 min▶
A backtest replays history as if it were live. For every stream and every minute t from 3 to 115, the nowcaster is given rows 1 to t-1 only, asked for the sum of orders in minutes t to t+4, and scored against what actually happened. Minute 3 is the first with enough history for a slope; minute 115 is the last whose five-minute horizon fits inside the 120. That is 112 windows a stream, 6,720 across the 60. The score is the mean absolute error over all of them, in orders per window.
The naive baseline is computed in the same loop, at the same windows: the sum of orders in minutes t-5 to t-1, offered as the forecast for t to t+4. "The next five minutes will look like the last five" is what a producer does in her head, and it is not stupid; it scores 11.97. Any nowcast that cannot beat it has no business in an earpiece. The rule is simple and it is not negotiable: the naive number goes in the same table as the model's number, every time, or the model's number means nothing.
| Forecaster | MAE, orders per 5-min window | Against naive |
|---|---|---|
| EWMA rate x room projection, alpha 0.1 | 9.41 | 21 percent lower |
| Same, alpha 0.3 | 10.84 | 9 percent lower |
| Same, alpha 0.6 | 11.28 | 6 percent lower |
| Naive: next five equals last five | 11.97 | the bar |
Score the sum, not the minutes. The producer acts on "about 40 orders in the next five", not on a per-minute path. Scoring each of the five minutes separately rewards a model for getting the shape right and the total wrong, which is the opposite of what she needs.
LiveAlpha: why the slow memory wins here3 min▶
Three alphas, three MAEs: 0.1 gives 9.41, 0.3 gives 10.84, 0.6 gives 11.28. The ordering is monotone and the gap is not small. With alpha 0.6 the rate estimate is mostly the last minute, and the last minute's rate in a room of 800 is a count of three or nine divided by 800, a number with enormous relative noise. The nowcaster then multiplies that noise by five projected rooms. With alpha 0.1 the newest minute gets a tenth of the weight and the estimate is effectively an average over the last ten or so, which is where the true rate lives.
This is a property of the data, not a law. A stream whose host changes what she is doing every two minutes has a rate that genuinely moves, and a slow alpha would lag it. The 60 Lumen Glow streams have segments of a few minutes each and a rate that mostly rides on the host, so the slow memory wins. The sweep in the build-along is there so you re-run it on your own streams rather than inheriting 0.1 as a constant.
On Priya's stream 16 (Monday 18:00, no giveaway, peak room 498) the per-minute order count is small enough that a single bundle order swings the rate visibly. The alpha 0.6 nowcast on that stream oscillates by tens of orders from one minute to the next while the actual five-minute totals barely move; the alpha 0.1 version tracks them. Small rooms are where the slow memory pays most, and small rooms are most streams.
Self-studyThe next rungs: statsforecast and a Kalman local level4 min▶
Tonight's nowcaster is the bottom rung of a ladder, and it is worth knowing the next two by name so you reach for them when the bottom rung stops beating naive.
- statsforecast 2.1.1 (Apache-2.0):
AutoETS,AutoThetaandMSTLon a frame ofunique_id, ds, ywithfreq="min", thensf.forecast(df, h=5, level=[90])for a prediction interval as well as a point. MSTL takesseason_length=[60]or a list if a stream has a repeating segment cycle. One caution: the package has had no release since 2024-09. It is stable and it works; it is not being extended. - statsmodels 0.15.0
UnobservedComponentswithlevel="local level": the textbook Kalman filter for a true room hidden under noisy per-minute reads.y_t = mu_t + e_t,mu_t = mu_{t-1} + eta_t; the filtered level is the room estimate andres.forecast(5)is the projection. It replaces the slope-and-damping rule with something that learns how noisy the room reads are and how fast the true room drifts.
Both need the same backtest loop and the same naive bar. A forecaster that is more sophisticated and scores 11.5 has lost to the arithmetic. The full method ladder, from naive through ETS and Theta to state space and beyond, with the backtesting discipline that goes with each rung, is a course on its own: learn time series forecasting with phoebe.
An alert that does not fire on noise
8 min liveA nowcast is a number every minute. A producer cannot act on a number every minute; she can act on a handful of moments a night. The alert is the rule that picks them, and a rule that fires on every noisy minute is worse than no rule, because by the third false alarm the earpiece is muted. Two conditions and a base rate, drawn on one stream.
LiveThe rule as the bench uses it3 min▶
The alert has two conditions and both must hold. First, the last three minutes of orders sum to under 70 percent of what the nowcast expected for those three minutes. Three, not one, because one minute under forecast happens constantly in a room where the count is a handful; three in a row is a slide. Seventy percent, not ninety, because a five-order miss on a forty-order forecast is noise and a fifteen-order miss is a room that has stopped buying. Second, the host's last CTA was six or more minutes ago.
This rule, followed exactly, is the "CTA on a dip" policy on session 8's replay bench: when it fires, the host is cued to do a CTA, and over 40 seeded nights of tonight's stream (Jules, Friday 20:00) that policy takes 20,847 dollars against the host's own plan at 18,198, plus 14.6 percent. The bench computes those means live in the browser. The rule you write tonight and the rule the bench runs are the same code.
The second condition is the one people want to delete, and it is the one that makes the rule usable. Without it, the rule fires during CTAs that are already running. A CTA minute has its orders arriving one to two minutes later, so the minute of the ask itself often looks like a shortfall; the rule would then cue a CTA into a CTA, the host would be asked to ask again, and the third time it happened she would take the earpiece out. Six minutes is two for the CTA to land, then a few more of the room converting on it, before it is reasonable to ask a second time.
LiveThe base rate, or why an alert without one is a guess3 min▶
Before a rule goes in anyone's ear, run it over the 60 historical streams with nothing done about it and count two things. How many times a night it fires on the host's own plan, which is the number of interruptions the producer is signing up for. And of those firings, what share were followed by an actual five-minute shortfall against the nowcast, which is how often the interruption was warranted. The build-along computes both from the history and prints them as a table; they are properties of your streams and your thresholds and they are not the same for a small room as for a large one.
Then move the thresholds and watch both numbers move. Loosen 70 percent to 85 and the rule fires more often on less; tighten six minutes to ten and it fires less often and later. There is no right setting, there is a trade the producer should make with the two numbers in front of her, and a rule shipped without them is a rule whose trade was made by whoever wrote the first draft.
| What to report | How it is computed on the history | What it tells the producer |
|---|---|---|
| Firings per stream | Count of minutes where both conditions hold, over 60 streams | Interruptions a night |
| Share of firings before a real dip | Of the firings, the share where the next five minutes fall under 70 percent of the nowcast | How often the interruption was warranted |
| Dips caught | Of the real dips, the share with a firing in the three minutes before | What it misses |
A base rate measured on a different stream mix is a different base rate. If your streams are half the size of these, the counts are noisier and the 70 percent threshold trips more. Rerun the table on your own history before you quote a firing rate to anyone.
LiveThe human in the loop2 min▶
The producer does not hear "fire". She hears a sentence: "orders under forecast, last CTA 8 minutes ago". That is the two conditions read out, and it is deliberately not an instruction. She can see the host, the chat and the product table; the rule can see three columns. She decides whether the cue is a CTA, a price reminder or nothing, because the host is mid-story and the story is working. The rule's job is to make sure she looks, at the right moment, with the reason in her ear.
Two words of the sentence carry the design. "Under forecast" says the shortfall is against what the room was expected to do, not against a number from a different night. "8 minutes ago" says there is room for an ask. When the leader track's session 5 teaches producers to coach live, this is the sentence they practise reacting to.
Self-studyWhat the nowcast will never see3 min▶
The nowcaster reads two columns of the minute table, orders and room, and knows nothing else. A change in how the feed is routing traffic shows up in the room only after it has happened, so the projection is late by exactly the amount it matters. A competitor's flash sale at the same hour pulls viewers out of the room for reasons the room curve cannot explain and the rate cannot anticipate. A product going out of stock stops orders dead while the nowcast keeps forecasting them for five more minutes.
None of that is a reason to add columns. It is the reason the horizon stays at five minutes. Every one of those shocks is invisible before it arrives and obvious within two minutes of arriving, and a five-minute forecast re-run every minute is wrong about it for at most a few windows before the new rate and the new slope take over. A thirty-minute forecast would be wrong for thirty. Short horizons are not a limitation the ladder grows out of; they are how a model with two inputs stays honest about the things it cannot see.
Backtest the nowcast, then write the alert
★ 20 min · everyone buildsFive steps, pandas and numpy only. The nowcast function, the backtest loop with the naive baseline in the same table, the alpha sweep, the alert rule with its base rate computed on the 60 streams, and a replay loop that prints the producer's sentence minute by minute for Priya's stream 16. The loop matches analyze.py's nowcast_backtest so your numbers are its numbers.
The nowcast function. Takes the order and room arrays of one stream and a minute t, uses only rows before t, returns the expected orders in t to t+4. The EWMA rate is carried between calls, so the function takes the previous rate and returns the new one.
The backtest loop, with the naive baseline in the same table. Every stream, every minute 3 to 115. The naive forecast is the last five minutes' orders. Both errors are collected at the same windows so the comparison is fair.
The alpha sweep. Three values, one table, the naive column repeated in every row so nobody reads the model column alone.
The alert rule and its base rate on the history. At each minute, compare the last three minutes' orders with the nowcast that was made for them three minutes earlier, and check the minutes since the last CTA. Then count firings per stream and the share followed by a real five-minute shortfall.
Replay one stream and print the producer's line. Priya's stream 16, minute by minute. The sentence is the two conditions read out; "fire" never appears.
The forecast you compare against must be the one made before the minutes it covers. Comparing the last three minutes with a nowcast made at t, which already saw them, is a rule that fires on its own hindsight. Keep the forecast dictionary keyed by the minute it was made, and look three minutes back.
Before session 8
30 min- Sweep the damping factor (0.4, 0.6, 0.8, 1.0) at alpha 0.1 and add the rows to the backtest table. Write one sentence on what a damping of 1.0 does to the error on streams with a giveaway opener, where the room moves fastest.
- Split the backtest error by room size: windows where the room is under 400 and windows where it is over 800. Report both MAEs and both naive MAEs. The nowcast's advantage over naive is not the same in both, and you should be able to say why before you look.
- Move the alert thresholds: 70 percent to 85 percent, and six minutes to ten. Produce the base-rate table for each of the four combinations and write two lines a producer could choose between, with the firings per stream and the share before a real dip on each.
- Fit a statsmodels 0.15.0
UnobservedComponents(room, level="local level")to one stream's room column and compare its five-step forecast with the slope-and-damping projection at ten minutes of your choosing. Do not add it to the nowcaster yet; just see whether the two disagree and where.
Three questions
The nowcast scores an MAE of 9.41 orders per five-minute window. Why does the backtest table also carry the naive "next five equals last five" rule at 11.97?
A forecast number without a baseline cannot be judged good or bad. Computed at the same 6,720 windows, the nowcast is 21 percent lower than naive. A more elaborate model that scored 11.5 would have lost to arithmetic.
Alpha 0.1 gives MAE 9.41, alpha 0.6 gives 11.28. Why does the slower memory win?
Alpha only touches the rate, not the room projection, and there is no training set. The per-viewer order rate of a host inside a stream is close to a constant with noise on it; the long memory averages the noise out.
The alert's second condition is "last CTA six or more minutes ago". What does it prevent?
Without the second condition the rule fires on its own remedy. The producer would be asked to cue a CTA while one is in progress, and after the third time the earpiece comes out. Six minutes is time for the ask to land and the room to convert on it.